[llvm] r330487 - [ObjCARC] Account for funclet token in storeStrong transform

Shoaib Meenai via llvm-commits llvm-commits at lists.llvm.org
Fri Apr 20 15:11:03 PDT 2018


Author: smeenai
Date: Fri Apr 20 15:11:03 2018
New Revision: 330487

URL: http://llvm.org/viewvc/llvm-project?rev=330487&view=rev
Log:
[ObjCARC] Account for funclet token in storeStrong transform

When creating a call to storeStrong in ObjCARCContract, ensure the call
gets the correct funclet token, otherwise WinEHPrepare will turn the
call (and all subsequent instructions) into unreachable.

We already have logic to do this for the ARC autorelease elision marker;
factor that out into a common function that's used for both. These are
the only two places in this transform that create call instructions.

Differential Revision: https://reviews.llvm.org/D45857

Added:
    llvm/trunk/test/Transforms/ObjCARC/contract-storestrong-funclet.ll
Modified:
    llvm/trunk/lib/Transforms/ObjCARC/ObjCARCContract.cpp

Modified: llvm/trunk/lib/Transforms/ObjCARC/ObjCARCContract.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/ObjCARC/ObjCARCContract.cpp?rev=330487&r1=330486&r2=330487&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/ObjCARC/ObjCARCContract.cpp (original)
+++ llvm/trunk/lib/Transforms/ObjCARC/ObjCARCContract.cpp Fri Apr 20 15:11:03 2018
@@ -91,8 +91,9 @@ namespace {
                         SmallPtrSetImpl<Instruction *> &DependingInstructions,
                         SmallPtrSetImpl<const BasicBlock *> &Visited);
 
-    void tryToContractReleaseIntoStoreStrong(Instruction *Release,
-                                             inst_iterator &Iter);
+    void tryToContractReleaseIntoStoreStrong(
+        Instruction *Release, inst_iterator &Iter,
+        const DenseMap<BasicBlock *, ColorVector> &BlockColors);
 
     void getAnalysisUsage(AnalysisUsage &AU) const override;
     bool doInitialization(Module &M) override;
@@ -306,6 +307,24 @@ findRetainForStoreStrongContraction(Valu
   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<Value *> Args, const Twine &NameStr,
+               Instruction *InsertBefore,
+               const DenseMap<BasicBlock *, ColorVector> &BlockColors) {
+  SmallVector<OperandBundleDef, 1> 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 @@ findRetainForStoreStrongContraction(Valu
 ///     (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<BasicBlock *, ColorVector> &BlockColors) {
   // See if we are releasing something that we just loaded.
   auto *Load = dyn_cast<LoadInst>(GetArgRCIdentityRoot(Release));
   if (!Load || !Load->isSimple())
@@ -386,7 +406,7 @@ void ObjCARCContract::tryToContractRelea
   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 @@ bool ObjCARCContract::tryToPeepholeInstr
             RVInstMarker->getString(),
             /*Constraints=*/"", /*hasSideEffects=*/true);
 
-        SmallVector<OperandBundleDef, 1> 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 @@ bool ObjCARCContract::tryToPeepholeInstr
     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.

Added: llvm/trunk/test/Transforms/ObjCARC/contract-storestrong-funclet.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ObjCARC/contract-storestrong-funclet.ll?rev=330487&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/ObjCARC/contract-storestrong-funclet.ll (added)
+++ llvm/trunk/test/Transforms/ObjCARC/contract-storestrong-funclet.ll Fri Apr 20 15:11:03 2018
@@ -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*)
+
+ at 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




More information about the llvm-commits mailing list