[llvm] r323009 - [ObjCARC] Do not turn a call to @objc_autoreleaseReturnValue into a call

Akira Hatanaka via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 19 15:51:14 PST 2018


Author: ahatanak
Date: Fri Jan 19 15:51:13 2018
New Revision: 323009

URL: http://llvm.org/viewvc/llvm-project?rev=323009&view=rev
Log:
[ObjCARC] Do not turn a call to @objc_autoreleaseReturnValue into a call
to @objc_autorelease if its operand is a PHI and the PHI has an
equivalent value that is used by a return instruction.

For example, ARC optimizer shouldn't replace the call in the following
example, as doing so breaks the AutoreleaseRV/RetainRV optimization:

  %v1 = bitcast i32* %v0 to i8*
  br label %bb3
bb2:
  %v3 = bitcast i32* %v2 to i8*
  br label %bb3
bb3:
  %p = phi i8* [ %v1, %bb1 ], [ %v3, %bb2 ]
  %retval = phi i32* [ %v0, %bb1 ], [ %v2, %bb2 ] ; equivalent to %p
  %v4 = tail call i8* @objc_autoreleaseReturnValue(i8* %p)
  ret i32* %retval

Also, make sure ObjCARCContract replaces @objc_autoreleaseReturnValue's
operand uses with its value so that the call gets tail-called.

rdar://problem/15894705

Modified:
    llvm/trunk/lib/Transforms/ObjCARC/ObjCARC.h
    llvm/trunk/lib/Transforms/ObjCARC/ObjCARCContract.cpp
    llvm/trunk/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
    llvm/trunk/test/Transforms/ObjCARC/contract-replace-arg-use.ll
    llvm/trunk/test/Transforms/ObjCARC/rv.ll

Modified: llvm/trunk/lib/Transforms/ObjCARC/ObjCARC.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/ObjCARC/ObjCARC.h?rev=323009&r1=323008&r2=323009&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/ObjCARC/ObjCARC.h (original)
+++ llvm/trunk/lib/Transforms/ObjCARC/ObjCARC.h Fri Jan 19 15:51:13 2018
@@ -82,6 +82,26 @@ static inline const Instruction *getretu
   return dyn_cast<InvokeInst>(Opnd);
 }
 
+/// Return the list of PHI nodes that are equivalent to PN.
+template<class PHINodeTy, class VectorTy>
+void getEquivalentPHIs(PHINodeTy &PN, VectorTy &PHIList) {
+  auto *BB = PN.getParent();
+  for (auto &P : BB->phis()) {
+    if (&P == &PN) // Do not add PN to the list.
+      continue;
+    unsigned I = 0, E = PN.getNumIncomingValues();
+    for (; I < E; ++I) {
+      auto *BB = PN.getIncomingBlock(I);
+      auto *PNOpnd = PN.getIncomingValue(I)->stripPointerCasts();
+      auto *POpnd = P.getIncomingValueForBlock(BB)->stripPointerCasts();
+      if (PNOpnd != POpnd)
+        break;
+    }
+    if (I == E)
+      PHIList.push_back(&P);
+  }
+}
+
 } // end namespace objcarc
 } // end namespace llvm
 

Modified: llvm/trunk/lib/Transforms/ObjCARC/ObjCARCContract.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/ObjCARC/ObjCARCContract.cpp?rev=323009&r1=323008&r2=323009&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/ObjCARC/ObjCARCContract.cpp (original)
+++ llvm/trunk/lib/Transforms/ObjCARC/ObjCARCContract.cpp Fri Jan 19 15:51:13 2018
@@ -618,8 +618,17 @@ bool ObjCARCContract::runOnFunction(Func
       else if (isa<GlobalAlias>(Arg) &&
                !cast<GlobalAlias>(Arg)->isInterposable())
         Arg = cast<GlobalAlias>(Arg)->getAliasee();
-      else
+      else {
+        // If Arg is a PHI node, get PHIs that are equivalent to it and replace
+        // their uses.
+        if (PHINode *PN = dyn_cast<PHINode>(Arg)) {
+          SmallVector<Value *, 1> PHIList;
+          getEquivalentPHIs(*PN, PHIList);
+          for (Value *PHI : PHIList)
+            ReplaceArgUses(PHI);
+        }
         break;
+      }
     }
 
     // Replace bitcast users of Arg that are dominated by Inst.

Modified: llvm/trunk/lib/Transforms/ObjCARC/ObjCARCOpts.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/ObjCARC/ObjCARCOpts.cpp?rev=323009&r1=323008&r2=323009&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/ObjCARC/ObjCARCOpts.cpp (original)
+++ llvm/trunk/lib/Transforms/ObjCARC/ObjCARCOpts.cpp Fri Jan 19 15:51:13 2018
@@ -652,6 +652,11 @@ void ObjCARCOpt::OptimizeAutoreleaseRVCa
 
   SmallVector<const Value *, 2> Users;
   Users.push_back(Ptr);
+
+  // Add PHIs that are equivalent to Ptr to Users.
+  if (const PHINode *PN = dyn_cast<PHINode>(Ptr))
+    getEquivalentPHIs(*PN, Users);
+
   do {
     Ptr = Users.pop_back_val();
     for (const User *U : Ptr->users()) {

Modified: llvm/trunk/test/Transforms/ObjCARC/contract-replace-arg-use.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ObjCARC/contract-replace-arg-use.ll?rev=323009&r1=323008&r2=323009&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/ObjCARC/contract-replace-arg-use.ll (original)
+++ llvm/trunk/test/Transforms/ObjCARC/contract-replace-arg-use.ll Fri Jan 19 15:51:13 2018
@@ -6,6 +6,7 @@ declare i8* @foo1()
 ; Check that ARC contraction replaces the function return with the value
 ; returned by @objc_autoreleaseReturnValue.
 
+; CHECK-LABEL: define i32* @autoreleaseRVTailCall(
 ; CHECK: %[[V0:[0-9]+]] = tail call i8* @objc_autoreleaseReturnValue(
 ; CHECK: %[[V1:[0-9]+]] = bitcast i8* %[[V0]] to i32*
 ; CHECK: ret i32* %[[V1]]
@@ -16,3 +17,30 @@ define i32* @autoreleaseRVTailCall() {
   %3 = tail call i8* @objc_autoreleaseReturnValue(i8* %1)
   ret i32* %2
 }
+
+declare i32* @foo2(i32);
+
+; CHECK-LABEL: define i32* @autoreleaseRVTailCallPhi(
+; CHECK: %[[PHIVAL:.*]] = phi i8* [ %{{.*}}, %bb1 ], [ %{{.*}}, %bb2 ]
+; CHECK: %[[RETVAL:.*]] = phi i32* [ %{{.*}}, %bb1 ], [ %{{.*}}, %bb2 ]
+; CHECK: %[[V4:.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* %[[PHIVAL]])
+; CHECK: %[[V0:.*]] = bitcast i8* %[[V4]] to i32*
+; CHECK: ret i32* %[[V0]]
+
+define i32* @autoreleaseRVTailCallPhi(i1 %cond) {
+entry:
+  br i1 %cond, label %bb1, label %bb2
+bb1:
+  %v0 = call i32* @foo2(i32 1)
+  %v1 = bitcast i32* %v0 to i8*
+  br label %bb3
+bb2:
+  %v2 = call i32* @foo2(i32 2)
+  %v3 = bitcast i32* %v2 to i8*
+  br label %bb3
+bb3:
+  %phival = phi i8* [ %v1, %bb1 ], [ %v3, %bb2 ]
+  %retval = phi i32* [ %v0, %bb1 ], [ %v2, %bb2 ]
+  %v4 = tail call i8* @objc_autoreleaseReturnValue(i8* %phival)
+  ret i32* %retval
+}

Modified: llvm/trunk/test/Transforms/ObjCARC/rv.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ObjCARC/rv.ll?rev=323009&r1=323008&r2=323009&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/ObjCARC/rv.ll (original)
+++ llvm/trunk/test/Transforms/ObjCARC/rv.ll Fri Jan 19 15:51:13 2018
@@ -333,6 +333,37 @@ bb2:
   ret i8* %v2
 }
 
+declare i32* @func27(i32);
+
+; Check that ObjCARCOpt::OptimizeAutoreleaseRVCall doesn't turn a call to
+; @objc_autoreleaseReturnValue into a call to @objc_autorelease when a return
+; instruction uses a value equivalent to @objc_autoreleaseReturnValue's operand.
+; In the code below, %phival and %retval are considered equivalent.
+
+; CHECK-LABEL: define i32* @test27(
+; CHECK: %[[PHIVAL:.*]] = phi i8* [ %{{.*}}, %bb1 ], [ %{{.*}}, %bb2 ]
+; CHECK: %[[RETVAL:.*]] = phi i32* [ %{{.*}}, %bb1 ], [ %{{.*}}, %bb2 ]
+; CHECK: tail call i8* @objc_autoreleaseReturnValue(i8* %[[PHIVAL]])
+; CHECK: ret i32* %[[RETVAL]]
+
+define i32* @test27(i1 %cond) {
+entry:
+  br i1 %cond, label %bb1, label %bb2
+bb1:
+  %v0 = call i32* @func27(i32 1)
+  %v1 = bitcast i32* %v0 to i8*
+  br label %bb3
+bb2:
+  %v2 = call i32* @func27(i32 2)
+  %v3 = bitcast i32* %v2 to i8*
+  br label %bb3
+bb3:
+  %phival = phi i8* [ %v1, %bb1 ], [ %v3, %bb2 ]
+  %retval = phi i32* [ %v0, %bb1 ], [ %v2, %bb2 ]
+  %v4 = tail call i8* @objc_autoreleaseReturnValue(i8* %phival)
+  ret i32* %retval
+}
+
 !0 = !{}
 
 ; CHECK: attributes [[NUW]] = { nounwind }




More information about the llvm-commits mailing list