diff --git a/clang/test/CodeGenObjC/convert-messages-to-runtime-calls.m b/clang/test/CodeGenObjC/convert-messages-to-runtime-calls.m --- a/clang/test/CodeGenObjC/convert-messages-to-runtime-calls.m +++ b/clang/test/CodeGenObjC/convert-messages-to-runtime-calls.m @@ -26,6 +26,12 @@ // MSGS: {{call.*@objc_msgSend}} // MSGS: {{call.*@objc_msgSend}} // MSGS: {{call.*@objc_msgSend}} + // We can't emit calls to the intrinsics are not allowed as they're marked + // `thisreturn`, which isn't guaranteed to be true for classes that define + // their own `-retain`, for example. + // CALLS-NOT: {{call.*@llvm.objc.retain}} + // CALLS-NOT: {{call.*@llvm.objc.release}} + // CALLS-NOT: {{tail call.*@llvm.objc.autorelease}} // CALLS: {{call.*@objc_alloc}} // CALLS: {{call.*@objc_allocWithZone}} // CALLS: {{call.*@objc_retain}} diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td --- a/llvm/include/llvm/IR/Intrinsics.td +++ b/llvm/include/llvm/IR/Intrinsics.td @@ -412,7 +412,8 @@ // eliminate retain and releases where possible. def int_objc_autorelease : Intrinsic<[llvm_ptr_ty], - [llvm_ptr_ty]>; + [llvm_ptr_ty], + [Returned>]>; def int_objc_autoreleasePoolPop : Intrinsic<[], [llvm_ptr_ty]>; def int_objc_autoreleasePoolPush : Intrinsic<[llvm_ptr_ty], []>; def int_objc_autoreleaseReturnValue : Intrinsic<[llvm_ptr_ty], @@ -433,13 +434,17 @@ llvm_ptrptr_ty]>; def int_objc_release : Intrinsic<[], [llvm_ptr_ty]>; def int_objc_retain : Intrinsic<[llvm_ptr_ty], - [llvm_ptr_ty]>; + [llvm_ptr_ty], + [Returned>]>; def int_objc_retainAutorelease : Intrinsic<[llvm_ptr_ty], - [llvm_ptr_ty]>; + [llvm_ptr_ty], + [Returned>]>; def int_objc_retainAutoreleaseReturnValue : Intrinsic<[llvm_ptr_ty], - [llvm_ptr_ty]>; + [llvm_ptr_ty], + [Returned>]>; def int_objc_retainAutoreleasedReturnValue : Intrinsic<[llvm_ptr_ty], - [llvm_ptr_ty]>; + [llvm_ptr_ty], + [Returned>]>; def int_objc_retainBlock : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty]>; def int_objc_storeStrong : Intrinsic<[], @@ -462,7 +467,8 @@ def int_objc_unretainedPointer : Intrinsic<[llvm_ptr_ty], [llvm_ptr_ty]>; def int_objc_retain_autorelease : Intrinsic<[llvm_ptr_ty], - [llvm_ptr_ty]>; + [llvm_ptr_ty], + [Returned>]>; def int_objc_sync_enter : Intrinsic<[llvm_i32_ty], [llvm_ptr_ty]>; def int_objc_sync_exit : Intrinsic<[llvm_i32_ty], diff --git a/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp b/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp --- a/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp +++ b/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp @@ -110,6 +110,16 @@ CallInst::TailCallKind TCK = CI->getTailCallKind(); NewCI->setTailCallKind(std::max(TCK, OverridingTCK)); + // Transfer the 'returned' attribute from the intrinsic to the call site. + // By applying this only to intrinsic call sites, we avoid applying it to + // non-ARC explicit calls to things like objc_retain which have not been + // auto-upgraded to use the intrinsics. + unsigned Index; + if (F.getAttributes().hasAttrSomewhere(Attribute::Returned, &Index) && + Index) + NewCI->addParamAttr(Index - AttributeList::FirstArgIndex, + Attribute::Returned); + if (!CI->use_empty()) CI->replaceAllUsesWith(NewCI); CI->eraseFromParent(); diff --git a/llvm/test/Transforms/PreISelIntrinsicLowering/objc-arc.ll b/llvm/test/Transforms/PreISelIntrinsicLowering/objc-arc.ll --- a/llvm/test/Transforms/PreISelIntrinsicLowering/objc-arc.ll +++ b/llvm/test/Transforms/PreISelIntrinsicLowering/objc-arc.ll @@ -6,7 +6,7 @@ define i8* @test_objc_autorelease(i8* %arg0) { ; CHECK-LABEL: test_objc_autorelease ; CHECK-NEXT: entry -; CHECK-NEXT: %0 = notail call i8* @objc_autorelease(i8* %arg0) +; CHECK-NEXT: %0 = notail call i8* @objc_autorelease(i8* returned %arg0) ; CHECK-NEXT: ret i8* %0 entry: %0 = call i8* @llvm.objc.autorelease(i8* %arg0) @@ -113,20 +113,31 @@ ret void } +define i8* @test_objc_retain_intrinsic(i8* %arg0) { +; CHECK-LABEL: test_objc_retain_intrinsic +; CHECK-NEXT: entry +; CHECK-NEXT: %0 = tail call i8* @objc_retain(i8* returned %arg0) +; CHECK-NEXT: ret i8* %0 +entry: + %0 = call i8* @llvm.objc.retain(i8* %arg0) + ret i8* %0 +} + +; Explicit objc_retain calls should not be upgraded to be "thisreturn". define i8* @test_objc_retain(i8* %arg0) { ; CHECK-LABEL: test_objc_retain ; CHECK-NEXT: entry -; CHECK-NEXT: %0 = tail call i8* @objc_retain(i8* %arg0) +; CHECK-NEXT: %0 = call i8* @objc_retain(i8* %arg0) ; CHECK-NEXT: ret i8* %0 entry: - %0 = call i8* @llvm.objc.retain(i8* %arg0) + %0 = call i8* @objc_retain(i8* %arg0) ret i8* %0 } define i8* @test_objc_retainAutorelease(i8* %arg0) { ; CHECK-LABEL: test_objc_retainAutorelease ; CHECK-NEXT: entry -; CHECK-NEXT: %0 = call i8* @objc_retainAutorelease(i8* %arg0) +; CHECK-NEXT: %0 = call i8* @objc_retainAutorelease(i8* returned %arg0) ; CHECK-NEXT: ret i8* %0 entry: %0 = call i8* @llvm.objc.retainAutorelease(i8* %arg0) @@ -136,7 +147,7 @@ define i8* @test_objc_retainAutoreleaseReturnValue(i8* %arg0) { ; CHECK-LABEL: test_objc_retainAutoreleaseReturnValue ; CHECK-NEXT: entry -; CHECK-NEXT: %0 = tail call i8* @objc_retainAutoreleaseReturnValue(i8* %arg0) +; CHECK-NEXT: %0 = tail call i8* @objc_retainAutoreleaseReturnValue(i8* returned %arg0) ; CHECK-NEXT: ret i8* %0 entry: %0 = tail call i8* @llvm.objc.retainAutoreleaseReturnValue(i8* %arg0) @@ -146,7 +157,7 @@ define i8* @test_objc_retainAutoreleasedReturnValue(i8* %arg0) { ; CHECK-LABEL: test_objc_retainAutoreleasedReturnValue ; CHECK-NEXT: entry -; CHECK-NEXT: %0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* %arg0) +; CHECK-NEXT: %0 = tail call i8* @objc_retainAutoreleasedReturnValue(i8* returned %arg0) ; CHECK-NEXT: ret i8* %0 entry: %0 = call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %arg0) @@ -226,7 +237,7 @@ define i8* @test_objc_retain_autorelease(i8* %arg0) { ; CHECK-LABEL: test_objc_retain_autorelease ; CHECK-NEXT: entry -; CHECK-NEXT: %0 = call i8* @objc_retain_autorelease(i8* %arg0) +; CHECK-NEXT: %0 = call i8* @objc_retain_autorelease(i8* returned %arg0) ; CHECK-NEXT: ret i8* %0 entry: %0 = call i8* @llvm.objc.retain.autorelease(i8* %arg0) @@ -265,6 +276,7 @@ declare void @llvm.objc.moveWeak(i8**, i8**) declare void @llvm.objc.release(i8*) declare i8* @llvm.objc.retain(i8*) +declare i8* @objc_retain(i8*) declare i8* @llvm.objc.retainAutorelease(i8*) declare i8* @llvm.objc.retainAutoreleaseReturnValue(i8*) declare i8* @llvm.objc.retainAutoreleasedReturnValue(i8*) @@ -281,6 +293,7 @@ attributes #0 = { nounwind } +; CHECK: declare i8* @objc_retain(i8*) [[NLB:#[0-9]+]] ; CHECK: declare i8* @objc_autorelease(i8*) ; CHECK: declare void @objc_autoreleasePoolPop(i8*) ; CHECK: declare i8* @objc_autoreleasePoolPush() @@ -291,8 +304,7 @@ ; CHECK: declare i8* @objc_loadWeak(i8**) ; CHECK: declare i8* @objc_loadWeakRetained(i8**) ; CHECK: declare void @objc_moveWeak(i8**, i8**) -; CHECK: declare void @objc_release(i8*) [[NLB:#[0-9]+]] -; CHECK: declare i8* @objc_retain(i8*) [[NLB]] +; CHECK: declare void @objc_release(i8*) [[NLB]] ; CHECK: declare i8* @objc_retainAutorelease(i8*) ; CHECK: declare i8* @objc_retainAutoreleaseReturnValue(i8*) ; CHECK: declare i8* @objc_retainAutoreleasedReturnValue(i8*)