1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-24 19:52:54 +01:00

ObjCARC: teach the cloner about funclets

In the case that the CallInst that is being moved has an associated
operand bundle which is a funclet, the move will construct an invalid
instruction.  The new site will have a different token and needs to be
reassociated with the new instruction.

Unfortunately, there is no way to alter the bundle after the
construction of the instruction.  Replace the call instruction cloning
with a custom helper to clone the instruction and reassociate the
funclet token.

llvm-svn: 327336
This commit is contained in:
Saleem Abdulrasool 2018-03-12 21:46:09 +00:00
parent 053deac4af
commit 6bf371c84a
2 changed files with 148 additions and 1 deletions

View File

@ -38,6 +38,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/EHPersonalities.h"
#include "llvm/Analysis/ObjCARCAliasAnalysis.h"
#include "llvm/Analysis/ObjCARCAnalysisUtils.h"
#include "llvm/Analysis/ObjCARCInstKind.h"
@ -684,6 +685,34 @@ void ObjCARCOpt::OptimizeAutoreleaseRVCall(Function &F,
DEBUG(dbgs() << "New: " << *AutoreleaseRV << "\n");
}
namespace {
Instruction *
CloneCallInstForBB(Instruction &I, BasicBlock &BB,
DenseMap<BasicBlock *, ColorVector> &BlockColors) {
auto *CI = dyn_cast<CallInst>(&I);
assert(CI && "CloneCallInst must receive a CallInst");
SmallVector<OperandBundleDef, 1> OpBundles;
for (unsigned I = 0, E = CI->getNumOperandBundles(); I != E; ++I) {
auto Bundle = CI->getOperandBundleAt(I);
// funclets will be reassociated in the future
if (Bundle.getTagID() == LLVMContext::OB_funclet)
continue;
OpBundles.emplace_back(Bundle);
}
if (!BlockColors.empty()) {
const ColorVector &CV = BlockColors.find(&BB)->second;
assert(CV.size() == 1 && "non-unique color for block!");
Instruction *EHPad = CV.front()->getFirstNonPHI();
if (EHPad->isEHPad())
OpBundles.emplace_back("funclet", EHPad);
}
return CallInst::Create(CI, OpBundles);
}
}
/// Visit each call, one at a time, and make simplifications without doing any
/// additional analysis.
void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
@ -691,6 +720,11 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
// Reset all the flags in preparation for recomputing them.
UsedInThisFunction = 0;
DenseMap<BasicBlock *, ColorVector> BlockColors;
if (F.hasPersonalityFn() &&
isFuncletEHPersonality(classifyEHPersonality(F.getPersonalityFn())))
BlockColors = colorEHFunclets(F);
// Visit all objc_* calls in F.
for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E; ) {
Instruction *Inst = &*I++;
@ -927,9 +961,10 @@ void ObjCARCOpt::OptimizeIndividualCalls(Function &F) {
Value *Incoming =
GetRCIdentityRoot(PN->getIncomingValue(i));
if (!IsNullOrUndef(Incoming)) {
CallInst *Clone = cast<CallInst>(CInst->clone());
Value *Op = PN->getIncomingValue(i);
Instruction *InsertPos = &PN->getIncomingBlock(i)->back();
CallInst *Clone = cast<CallInst>(CloneCallInstForBB(
*CInst, *InsertPos->getParent(), BlockColors));
if (Op->getType() != ParamTy)
Op = new BitCastInst(Op, ParamTy, "", InsertPos);
Clone->setArgOperand(0, Op);

View File

@ -0,0 +1,112 @@
; RUN: opt -mtriple x86_64-unknown-windows-msvc -objc-arc -S -o - %s | FileCheck %s
; bool g();
; id h();
;
; void f() {
; id a = nullptr;
; if (g())
; a = h();
; id b = nullptr;
; g();
; }
declare zeroext i1 @"\01?g@@YA_NXZ"() local_unnamed_addr
declare i8* @"\01?h@@YAPEAUobjc_object@@XZ"() local_unnamed_addr
declare dllimport void @objc_release(i8*) local_unnamed_addr
declare dllimport i8* @objc_retainAutoreleasedReturnValue(i8* returned) local_unnamed_addr
declare i32 @__CxxFrameHandler3(...)
define void @"\01?f@@YAXXZ"() local_unnamed_addr personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%call = invoke zeroext i1 @"\01?g@@YA_NXZ"()
to label %invoke.cont unwind label %ehcleanup6
invoke.cont: ; preds = %entry
br i1 %call, label %if.then, label %if.end
if.then: ; preds = %invoke.cont
%call2 = invoke i8* @"\01?h@@YAPEAUobjc_object@@XZ"()
to label %invoke.cont1 unwind label %ehcleanup6
invoke.cont1: ; preds = %if.then
%0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %call2)
tail call void @objc_release(i8* null), !clang.imprecise_release !1
br label %if.end
if.end: ; preds = %invoke.cont1, %invoke.cont
%a.0 = phi i8* [ %call2, %invoke.cont1 ], [ null, %invoke.cont ]
%call4 = invoke zeroext i1 @"\01?g@@YA_NXZ"()
to label %invoke.cont3 unwind label %ehcleanup
invoke.cont3: ; preds = %if.end
tail call void @objc_release(i8* null), !clang.imprecise_release !1
tail call void @objc_release(i8* %a.0), !clang.imprecise_release !1
ret void
ehcleanup: ; preds = %if.end
%1 = cleanuppad within none []
call void @objc_release(i8* null) [ "funclet"(token %1) ], !clang.imprecise_release !1
cleanupret from %1 unwind label %ehcleanup6
ehcleanup6: ; preds = %ehcleanup, %if.then, %entry
%a.1 = phi i8* [ %a.0, %ehcleanup ], [ null, %if.then ], [ null, %entry ]
%2 = cleanuppad within none []
call void @objc_release(i8* %a.1) [ "funclet"(token %2) ], !clang.imprecise_release !1
cleanupret from %2 unwind to caller
}
; CHECK-LABEL: ?f@@YAXXZ
; CHECK: call void @objc_release(i8* {{.*}}) {{.*}}[ "funclet"(token %1) ]
; CHECK-NOT: call void @objc_release(i8* {{.*}}) {{.*}}[ "funclet"(token %2) ]
define void @"\01?i@@YAXXZ"() local_unnamed_addr personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
%call = invoke zeroext i1 @"\01?g@@YA_NXZ"()
to label %invoke.cont unwind label %ehcleanup6
invoke.cont: ; preds = %entry
br i1 %call, label %if.then, label %if.end
if.then: ; preds = %invoke.cont
%call2 = invoke i8* @"\01?h@@YAPEAUobjc_object@@XZ"()
to label %invoke.cont1 unwind label %ehcleanup6
invoke.cont1: ; preds = %if.then
%0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %call2)
tail call void @objc_release(i8* null), !clang.imprecise_release !1
br label %if.end
if.end: ; preds = %invoke.cont1, %invoke.cont
%a.0 = phi i8* [ %call2, %invoke.cont1 ], [ null, %invoke.cont ]
%call4 = invoke zeroext i1 @"\01?g@@YA_NXZ"()
to label %invoke.cont3 unwind label %ehcleanup
invoke.cont3: ; preds = %if.end
tail call void @objc_release(i8* null), !clang.imprecise_release !1
tail call void @objc_release(i8* %a.0), !clang.imprecise_release !1
ret void
ehcleanup: ; preds = %if.end
%1 = cleanuppad within none []
call void @objc_release(i8* null) [ "funclet"(token %1) ], !clang.imprecise_release !1
br label %ehcleanup.1
ehcleanup.1:
cleanupret from %1 unwind label %ehcleanup6
ehcleanup6: ; preds = %ehcleanup, %if.then, %entry
%a.1 = phi i8* [ %a.0, %ehcleanup.1 ], [ null, %if.then ], [ null, %entry ]
%2 = cleanuppad within none []
call void @objc_release(i8* %a.1) [ "funclet"(token %2) ], !clang.imprecise_release !1
cleanupret from %2 unwind to caller
}
; CHECK-LABEL: ?i@@YAXXZ
; CHECK: call void @objc_release(i8* {{.*}}) {{.*}}[ "funclet"(token %1) ]
; CHECK-NOT: call void @objc_release(i8* {{.*}}) {{.*}}[ "funclet"(token %2) ]
!1 = !{}