]> granicus.if.org Git - llvm/commitdiff
Do not call replaceAllUsesWith to upgrade calls to ARC runtime functions
authorAkira Hatanaka <ahatanaka@apple.com>
Mon, 12 Aug 2019 23:53:23 +0000 (23:53 +0000)
committerAkira Hatanaka <ahatanaka@apple.com>
Mon, 12 Aug 2019 23:53:23 +0000 (23:53 +0000)
to intrinsic calls

This fixes a bug in r368311.

It turns out that the ARC runtime functions in the IR can have pointer
parameter types that are not i8* or i8**. Instead of RAUWing normal
functions with intrinsics, manually bitcast the arguments before passing
them to the intrinsic functions and bitcast the return value back to the
type of the original call instruction.

rdar://problem/54125406

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@368634 91177308-0d34-0410-b5e6-96231b3b80d8

lib/IR/AutoUpgrade.cpp
test/Bitcode/upgrade-arc-runtime-calls.bc
test/Bitcode/upgrade-arc-runtime-calls.ll
test/Bitcode/upgrade-mrr-runtime-calls.bc

index 6d1305393e13b6c8def99ce82f64c8a356375282..6e70a0063f0843f3110aab22a01d9b3615dec0e8 100644 (file)
@@ -3855,6 +3855,8 @@ bool llvm::UpgradeRetainReleaseMarker(Module &M) {
 }
 
 void llvm::UpgradeARCRuntimeCalls(Module &M) {
+  // This lambda converts normal function calls to ARC runtime functions to
+  // intrinsic calls.
   auto UpgradeToIntrinsic = [&](const char *OldFunc,
                                 llvm::Intrinsic::ID IntrinsicFunc) {
     Function *Fn = M.getFunction(OldFunc);
@@ -3863,11 +3865,43 @@ void llvm::UpgradeARCRuntimeCalls(Module &M) {
       return;
 
     Function *NewFn = llvm::Intrinsic::getDeclaration(&M, IntrinsicFunc);
-    Fn->replaceAllUsesWith(NewFn);
-    Fn->eraseFromParent();
+    for (Use &U : Fn->uses()) {
+      CallInst *CI = dyn_cast<CallInst>(U.getUser());
+      if (!CI || CI->getCalledFunction() != Fn)
+        continue;
+
+      IRBuilder<> Builder(CI->getParent(), CI->getIterator());
+      FunctionType *NewFuncTy = NewFn->getFunctionType();
+      SmallVector<Value *, 2> Args;
+
+      for (unsigned I = 0, E = CI->getNumArgOperands(); I != E; ++I) {
+        Value *Arg = CI->getArgOperand(I);
+        // Bitcast argument to the parameter type of the new function if it's
+        // not a variadic argument.
+        if (I < NewFuncTy->getNumParams())
+          Arg = Builder.CreateBitCast(Arg, NewFuncTy->getParamType(I));
+        Args.push_back(Arg);
+      }
+
+      // Create a call instruction that calls the new function.
+      CallInst *NewCall = Builder.CreateCall(NewFuncTy, NewFn, Args);
+      NewCall->setTailCallKind(cast<CallInst>(CI)->getTailCallKind());
+      NewCall->setName(CI->getName());
+
+      // Bitcast the return value back to the type of the old call.
+      Value *NewRetVal = Builder.CreateBitCast(NewCall, CI->getType());
+
+      if (!CI->use_empty())
+        CI->replaceAllUsesWith(NewRetVal);
+      CI->eraseFromParent();
+    }
+
+    if (Fn->use_empty())
+      Fn->eraseFromParent();
   };
 
-  // Unconditionally convert "clang.arc.use" to "llvm.objc.clang.arc.use".
+  // Unconditionally convert a call to "clang.arc.use" to a call to
+  // "llvm.objc.clang.arc.use".
   UpgradeToIntrinsic("clang.arc.use", llvm::Intrinsic::objc_clang_arc_use);
 
   // Return if the bitcode doesn't have the arm64 retainAutoreleasedReturnValue
index 5fedabb890485913715d284a7d392d635a49ccf4..35c78004a951a5ff5e7c9fc7d5d33a5ad6615f67 100644 (file)
Binary files a/test/Bitcode/upgrade-arc-runtime-calls.bc and b/test/Bitcode/upgrade-arc-runtime-calls.bc differ
index 512443b04119ecdb0cdd4fa346eb623c523f7434..dbccff2a5b0d15cfb338f58be0af1ca5192ba637 100644 (file)
@@ -8,14 +8,62 @@
 ; RUN: llvm-dis < %S/upgrade-arc-runtime-calls.bc | FileCheck -check-prefixes=ARC %s
 ; RUN: llvm-dis < %S/upgrade-mrr-runtime-calls.bc | FileCheck -check-prefixes=MRR %s
 
-// ARC: define void @testRuntimeCalls(i8* %[[A:.*]], i8** %[[B:.*]], i8** %[[C:.*]]) {
+define void @testRuntimeCalls(i8* %a, i8** %b, i8** %c, i32* %d, i32** %e) personality i32 (...)* @__gxx_personality_v0 {
+entry:
+  %v0 = tail call i8* @objc_autorelease(i8* %a) #0
+  tail call void @objc_autoreleasePoolPop(i8* %a) #0
+  %v1 = tail call i8* @objc_autoreleasePoolPush() #0
+  %v2 = tail call i8* @objc_autoreleaseReturnValue(i8* %a) #0
+  tail call void @objc_copyWeak(i8** %b, i8** %c) #0
+  tail call void @objc_destroyWeak(i8** %b) #0
+  %v3 = tail call i32* @objc_initWeak(i32** %e, i32* %d) #0
+  %v4 = tail call i8* @objc_loadWeak(i8** %b) #0
+  %v5 = tail call i8* @objc_loadWeakRetained(i8** %b) #0
+  tail call void @objc_moveWeak(i8** %b, i8** %c) #0
+  tail call void @objc_release(i8* %a) #0
+  %v6 = tail call i8* @objc_retain(i8* %a) #0
+  %v7 = tail call i8* @objc_retainAutorelease(i8* %a) #0
+  %v8 = tail call i8* @objc_retainAutoreleaseReturnValue(i8* %a) #0
+  %v9 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %a) #0
+  %v10 = tail call i8* @objc_retainBlock(i8* %a) #0
+  tail call void @objc_storeStrong(i8** %b, i8* %a) #0
+  %v11 = tail call i8* @objc_storeWeak(i8** %b, i8* %a) #0
+  tail call void (...) @clang.arc.use(i8* %a) #0
+  %v12 = tail call i8* @objc_unsafeClaimAutoreleasedReturnValue(i8* %a) #0
+  %v13 = tail call i8* @objc_retainedObject(i8* %a) #0
+  %v14 = tail call i8* @objc_unretainedObject(i8* %a) #0
+  %v15 = tail call i8* @objc_unretainedPointer(i8* %a) #0
+  %v16 = tail call i8* @objc_retain.autorelease(i8* %a) #0
+  %v17 = tail call i32 @objc_sync.enter(i8* %a) #0
+  %v18 = tail call i32 @objc_sync.exit(i8* %a) #0
+  tail call void @objc_arc_annotation_topdown_bbstart(i8** %b, i8** %c) #0
+  tail call void @objc_arc_annotation_topdown_bbend(i8** %b, i8** %c) #0
+  tail call void @objc_arc_annotation_bottomup_bbstart(i8** %b, i8** %c) #0
+  tail call void @objc_arc_annotation_bottomup_bbend(i8** %b, i8** %c) #0
+  invoke void @objc_autoreleasePoolPop(i8* %a)
+          to label %normalBlock unwind label %unwindBlock
+normalBlock:
+  ret void
+unwindBlock:
+  %ll = landingpad { i8*, i32 }
+          cleanup
+  ret void
+}
+
+// Check that auto-upgrader converts function calls to intrinsic calls. Note that
+// the auto-upgrader doesn't touch invoke instructions.
+
+// ARC: define void @testRuntimeCalls(i8* %[[A:.*]], i8** %[[B:.*]], i8** %[[C:.*]], i32* %[[D:.*]], i32** %[[E:.*]]) personality
 // ARC: %[[V0:.*]] = tail call i8* @llvm.objc.autorelease(i8* %[[A]])
 // ARC-NEXT: tail call void @llvm.objc.autoreleasePoolPop(i8* %[[A]])
 // ARC-NEXT: %[[V1:.*]] = tail call i8* @llvm.objc.autoreleasePoolPush()
 // ARC-NEXT: %[[V2:.*]] = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %[[A]])
 // ARC-NEXT: tail call void @llvm.objc.copyWeak(i8** %[[B]], i8** %[[C]])
 // ARC-NEXT: tail call void @llvm.objc.destroyWeak(i8** %[[B]])
-// ARC-NEXT: %[[V3:.*]] = tail call i8* @llvm.objc.initWeak(i8** %[[B]], i8* %[[A]])
+// ARC-NEXT: %[[V100:.*]] = bitcast i32** %[[E]] to i8**
+// ARC-NEXT: %[[V101:.*]] = bitcast i32* %[[D]] to i8*
+// ARC-NEXT: %[[V102:.*]] = tail call i8* @llvm.objc.initWeak(i8** %[[V100]], i8* %[[V101]])
+// ARC-NEXT: %[[V103:.*]] = bitcast i8* %[[V102]] to i32*
 // ARC-NEXT: %[[V4:.*]] = tail call i8* @llvm.objc.loadWeak(i8** %[[B]])
 // ARC-NEXT: %[[V5:.*]] = tail call i8* @llvm.objc.loadWeakRetained(i8** %[[B]])
 // ARC-NEXT: tail call void @llvm.objc.moveWeak(i8** %[[B]], i8** %[[C]])
 // ARC-NEXT: tail call void @llvm.objc.arc.annotation.topdown.bbend(i8** %[[B]], i8** %[[C]])
 // ARC-NEXT: tail call void @llvm.objc.arc.annotation.bottomup.bbstart(i8** %[[B]], i8** %[[C]])
 // ARC-NEXT: tail call void @llvm.objc.arc.annotation.bottomup.bbend(i8** %[[B]], i8** %[[C]])
-// ARC-NEXT: ret void
+// ARC-NEXT: invoke void @objc_autoreleasePoolPop(i8* %[[A]])
 
-// MRR: define void @testRuntimeCalls(i8* %[[A:.*]], i8** %[[B:.*]], i8** %[[C:.*]]) {
+// MRR: define void @testRuntimeCalls(i8* %[[A:.*]], i8** %[[B:.*]], i8** %[[C:.*]], i32* %[[D:.*]], i32** %[[E:.*]]) personality
 // MRR: %[[V0:.*]] = tail call i8* @objc_autorelease(i8* %[[A]])
 // MRR-NEXT: tail call void @objc_autoreleasePoolPop(i8* %[[A]])
 // MRR-NEXT: %[[V1:.*]] = tail call i8* @objc_autoreleasePoolPush()
 // MRR-NEXT: %[[V2:.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* %[[A]])
 // MRR-NEXT: tail call void @objc_copyWeak(i8** %[[B]], i8** %[[C]])
 // MRR-NEXT: tail call void @objc_destroyWeak(i8** %[[B]])
-// MRR-NEXT: %[[V3:.*]] = tail call i8* @objc_initWeak(i8** %[[B]], i8* %[[A]])
+// MRR-NEXT: %[[V3:.*]] = tail call i32* @objc_initWeak(i32** %[[E]], i32* %[[D]])
 // MRR-NEXT: %[[V4:.*]] = tail call i8* @objc_loadWeak(i8** %[[B]])
 // MRR-NEXT: %[[V5:.*]] = tail call i8* @objc_loadWeakRetained(i8** %[[B]])
 // MRR-NEXT: tail call void @objc_moveWeak(i8** %[[B]], i8** %[[C]])
 // MRR-NEXT: tail call void @objc_arc_annotation_topdown_bbend(i8** %[[B]], i8** %[[C]])
 // MRR-NEXT: tail call void @objc_arc_annotation_bottomup_bbstart(i8** %[[B]], i8** %[[C]])
 // MRR-NEXT: tail call void @objc_arc_annotation_bottomup_bbend(i8** %[[B]], i8** %[[C]])
-// MRR-NEXT: ret void
+// MRR-NEXT: invoke void @objc_autoreleasePoolPop(i8* %[[A]])
index 877b2b4eb49367cdead7d8932fab84d34d4b006c..64c44c8696ff2d706b85339f3d3eb3c09844bd51 100644 (file)
Binary files a/test/Bitcode/upgrade-mrr-runtime-calls.bc and b/test/Bitcode/upgrade-mrr-runtime-calls.bc differ