[llvm] r327336 - ObjCARC: teach the cloner about funclets

Saleem Abdulrasool via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 12 14:46:09 PDT 2018


Author: compnerd
Date: Mon Mar 12 14:46:09 2018
New Revision: 327336

URL: http://llvm.org/viewvc/llvm-project?rev=327336&view=rev
Log:
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.

Added:
    llvm/trunk/test/Transforms/ObjCARC/funclet.ll
Modified:
    llvm/trunk/lib/Transforms/ObjCARC/ObjCARCOpts.cpp

Modified: llvm/trunk/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/ObjCARC/ObjCARCOpts.cpp?rev=327336&r1=327335&r2=327336&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/ObjCARC/ObjCARCOpts.cpp (original)
+++ llvm/trunk/lib/Transforms/ObjCARC/ObjCARCOpts.cpp Mon Mar 12 14:46:09 2018
@@ -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::OptimizeAutoreleaseRVCa
   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
   // 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
             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);

Added: llvm/trunk/test/Transforms/ObjCARC/funclet.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ObjCARC/funclet.ll?rev=327336&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/ObjCARC/funclet.ll (added)
+++ llvm/trunk/test/Transforms/ObjCARC/funclet.ll Mon Mar 12 14:46:09 2018
@@ -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 = !{}
+




More information about the llvm-commits mailing list