Index: lib/Transforms/ObjCARC/ObjCARCContract.cpp =================================================================== --- lib/Transforms/ObjCARC/ObjCARCContract.cpp +++ lib/Transforms/ObjCARC/ObjCARCContract.cpp @@ -91,8 +91,9 @@ SmallPtrSetImpl &DependingInstructions, SmallPtrSetImpl &Visited); - void tryToContractReleaseIntoStoreStrong(Instruction *Release, - inst_iterator &Iter); + void tryToContractReleaseIntoStoreStrong( + Instruction *Release, inst_iterator &Iter, + const DenseMap &BlockColors); void getAnalysisUsage(AnalysisUsage &AU) const override; bool doInitialization(Module &M) override; @@ -306,6 +307,24 @@ return Retain; } +/// Create a call instruction with the correct funclet token. Should be used +/// instead of calling CallInst::Create directly. +static CallInst * +createCallInst(Value *Func, ArrayRef Args, const Twine &NameStr, + Instruction *InsertBefore, + const DenseMap &BlockColors) { + SmallVector OpBundles; + if (!BlockColors.empty()) { + const ColorVector &CV = BlockColors.find(InsertBefore->getParent())->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(Func, Args, OpBundles, NameStr, InsertBefore); +} + /// Attempt to merge an objc_release with a store, load, and objc_retain to form /// an objc_storeStrong. An objc_storeStrong: /// @@ -333,8 +352,9 @@ /// (4). /// 2. We need to make sure that any re-orderings of (1), (2), (3), (4) are /// safe. -void ObjCARCContract::tryToContractReleaseIntoStoreStrong(Instruction *Release, - inst_iterator &Iter) { +void ObjCARCContract::tryToContractReleaseIntoStoreStrong( + Instruction *Release, inst_iterator &Iter, + const DenseMap &BlockColors) { // See if we are releasing something that we just loaded. auto *Load = dyn_cast(GetArgRCIdentityRoot(Release)); if (!Load || !Load->isSimple()) @@ -386,7 +406,7 @@ if (Args[1]->getType() != I8X) Args[1] = new BitCastInst(Args[1], I8X, "", Store); Constant *Decl = EP.get(ARCRuntimeEntryPointKind::StoreStrong); - CallInst *StoreStrong = CallInst::Create(Decl, Args, "", Store); + CallInst *StoreStrong = createCallInst(Decl, Args, "", Store, BlockColors); StoreStrong->setDoesNotThrow(); StoreStrong->setDebugLoc(Store->getDebugLoc()); @@ -462,16 +482,7 @@ RVInstMarker->getString(), /*Constraints=*/"", /*hasSideEffects=*/true); - SmallVector OpBundles; - if (!BlockColors.empty()) { - const ColorVector &CV = BlockColors.find(Inst->getParent())->second; - assert(CV.size() == 1 && "non-unique color for block!"); - Instruction *EHPad = CV.front()->getFirstNonPHI(); - if (EHPad->isEHPad()) - OpBundles.emplace_back("funclet", EHPad); - } - - CallInst::Create(IA, None, OpBundles, "", Inst); + createCallInst(IA, None, "", Inst, BlockColors); } decline_rv_optimization: return false; @@ -496,7 +507,7 @@ case ARCInstKind::Release: // Try to form an objc store strong from our release. If we fail, there is // nothing further to do below, so continue. - tryToContractReleaseIntoStoreStrong(Inst, Iter); + tryToContractReleaseIntoStoreStrong(Inst, Iter, BlockColors); return true; case ARCInstKind::User: // Be conservative if the function has any alloca instructions. Index: test/Transforms/ObjCARC/contract-storestrong-funclet.ll =================================================================== --- /dev/null +++ test/Transforms/ObjCARC/contract-storestrong-funclet.ll @@ -0,0 +1,37 @@ +; RUN: opt -mtriple=i686-unknown-windows-msvc -objc-arc-contract -S -o - %s | FileCheck %s + +declare void @f() +declare i32 @__CxxFrameHandler3(...) +declare dllimport i8* @objc_retain(i8*) +declare dllimport i8* @objc_retainAutoreleasedReturnValue(i8*) +declare dllimport void @objc_release(i8*) + +@x = external global i8* + +define void @g(i8* %p) personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { + invoke void @f() to label %invoke.cont unwind label %ehcleanup + +invoke.cont: + %call = tail call i8* @objc_retain(i8* %p) nounwind + %tmp = load i8*, i8** @x, align 4 + store i8* %call, i8** @x, align 4 + tail call void @objc_release(i8* %tmp) nounwind + ret void + +ehcleanup: + %1 = cleanuppad within none [] + %call1 = tail call i8* @objc_retain(i8* %p) nounwind [ "funclet"(token %1) ] + %tmp1 = load i8*, i8** @x, align 4 + store i8* %call1, i8** @x, align 4 + tail call void @objc_release(i8* %tmp1) nounwind [ "funclet"(token %1) ] + cleanupret from %1 unwind to caller +} + +; CHECK-LABEL: invoke.cont: +; CHECK: tail call void @objc_storeStrong(i8** @x, i8* %p) #0{{$}} +; CHECK: ret void + +; CHECK-LABEL: ehcleanup: +; CHECK: %1 = cleanuppad within none [] +; CHECK: tail call void @objc_storeStrong(i8** @x, i8* %p) #0 [ "funclet"(token %1) ] +; CHECK: cleanupret from %1 unwind to caller