From df76f1ea801a60a422812b20bd0bfa6ab51cecf8 Mon Sep 17 00:00:00 2001 From: Chad Rosier Date: Wed, 12 Dec 2012 17:52:21 +0000 Subject: [PATCH] Marking the objc_autoreleaseReturnValue and objc_retainAutoreleaseReturnValue call sites as tail calls unconditionally. While it's theoretically true that this is just an optimization, it's an optimization that we very much want to happen even at -O0, or else ARC applications become substantially harder to debug. See r169796 for the llvm/fast-isel side of things. rdar://12553082 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@169996 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGObjC.cpp | 11 ++++++++--- test/CodeGenObjC/arc-blocks.m | 4 ++-- test/CodeGenObjC/arc-unopt.m | 4 ++-- test/CodeGenObjC/arc-weak-property.m | 2 +- test/CodeGenObjC/arc.m | 8 ++++---- test/CodeGenObjC/objc-arc-container-subscripting.m | 2 +- 6 files changed, 18 insertions(+), 13 deletions(-) diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index c90e4eca84..deac5f6aa4 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -1725,7 +1725,8 @@ static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM, static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF, llvm::Value *value, llvm::Constant *&fn, - StringRef fnName) { + StringRef fnName, + bool isTailCall = false) { if (isa(value)) return value; if (!fn) { @@ -1742,6 +1743,8 @@ static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF, // Call the function. llvm::CallInst *call = CGF.Builder.CreateCall(fn, value); call->setDoesNotThrow(); + if (isTailCall) + call->setTailCall(); // Cast the result back to the original type. return CGF.Builder.CreateBitCast(call, origType); @@ -2054,7 +2057,8 @@ llvm::Value * CodeGenFunction::EmitARCAutoreleaseReturnValue(llvm::Value *value) { return emitARCValueOperation(*this, value, CGM.getARCEntrypoints().objc_autoreleaseReturnValue, - "objc_autoreleaseReturnValue"); + "objc_autoreleaseReturnValue", + /*isTailCall*/ true); } /// Do a fused retain/autorelease of the given object. @@ -2063,7 +2067,8 @@ llvm::Value * CodeGenFunction::EmitARCRetainAutoreleaseReturnValue(llvm::Value *value) { return emitARCValueOperation(*this, value, CGM.getARCEntrypoints().objc_retainAutoreleaseReturnValue, - "objc_retainAutoreleaseReturnValue"); + "objc_retainAutoreleaseReturnValue", + /*isTailCall*/ true); } /// Do a fused retain/autorelease of the given object. diff --git a/test/CodeGenObjC/arc-blocks.m b/test/CodeGenObjC/arc-blocks.m index f87f9a4b23..48c4f08c71 100644 --- a/test/CodeGenObjC/arc-blocks.m +++ b/test/CodeGenObjC/arc-blocks.m @@ -16,7 +16,7 @@ int (^test1(int x))(void) { // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) nounwind // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i32 ()* // CHECK-NEXT: [[T4:%.*]] = bitcast i32 ()* [[T3]] to i8* - // CHECK-NEXT: [[T5:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T4]]) nounwind + // CHECK-NEXT: [[T5:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T4]]) nounwind // CHECK-NEXT: [[T6:%.*]] = bitcast i8* [[T5]] to i32 ()* // CHECK-NEXT: ret i32 ()* [[T6]] return ^{ return x; }; @@ -314,7 +314,7 @@ id test9(void) { // CHECK: load i8** getelementptr // CHECK-NEXT: bitcast i8* // CHECK-NEXT: call i8* -// CHECK-NEXT: call i8* @objc_autoreleaseReturnValue +// CHECK-NEXT: tail call i8* @objc_autoreleaseReturnValue // CHECK-NEXT: ret i8* // CHECK: call i8* @test9_produce() diff --git a/test/CodeGenObjC/arc-unopt.m b/test/CodeGenObjC/arc-unopt.m index c319bf260f..84f5d34b19 100644 --- a/test/CodeGenObjC/arc-unopt.m +++ b/test/CodeGenObjC/arc-unopt.m @@ -9,7 +9,7 @@ Test0 *test0(void) { // CHECK: [[LD:%.*]] = load [[TEST0:%.*]]** @test0_helper // CHECK-NEXT: [[T0:%.*]] = bitcast [[TEST0]]* [[LD]] to i8* - // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleaseReturnValue(i8* [[T0]]) + // CHECK-NEXT: [[T1:%.*]] = tail call i8* @objc_retainAutoreleaseReturnValue(i8* [[T0]]) // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to [[TEST0]]* // CHECK-NEXT: ret [[TEST0]]* [[T2]] } @@ -19,7 +19,7 @@ id test1(void) { return test1_helper; // CHECK: [[LD:%.*]] = load i8** @test1_helper - // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retainAutoreleaseReturnValue(i8* [[LD]]) + // CHECK-NEXT: [[T0:%.*]] = tail call i8* @objc_retainAutoreleaseReturnValue(i8* [[LD]]) // CHECK-NEXT: ret i8* [[T0]] } diff --git a/test/CodeGenObjC/arc-weak-property.m b/test/CodeGenObjC/arc-weak-property.m index 0a6b2a63bf..e8d57bcfe5 100644 --- a/test/CodeGenObjC/arc-weak-property.m +++ b/test/CodeGenObjC/arc-weak-property.m @@ -22,7 +22,7 @@ // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8* [[T2]], i64 [[T1]] // CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to i8** // CHECK-NEXT: [[T5:%.*]] = call i8* @objc_loadWeakRetained(i8** [[T4]]) -// CHECK-NEXT: [[T6:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T5]]) +// CHECK-NEXT: [[T6:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T5]]) // CHECK-NEXT: ret i8* [[T6]] // CHECK: define internal void @"\01-[WeakPropertyTest setPROP:]" diff --git a/test/CodeGenObjC/arc.m b/test/CodeGenObjC/arc.m index 43a7a30967..bac966165a 100644 --- a/test/CodeGenObjC/arc.m +++ b/test/CodeGenObjC/arc.m @@ -29,7 +29,7 @@ id test1(id x) { // CHECK-NEXT: call void @objc_release(i8* [[T0]]) // CHECK-NEXT: [[T1:%.*]] = load i8** [[X]] // CHECK-NEXT: call void @objc_release(i8* [[T1]]) - // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[RET]]) + // CHECK-NEXT: [[T1:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[RET]]) // CHECK-NEXT: ret i8* [[T1]] id y; return y; @@ -156,7 +156,7 @@ id test4() { // Retain/release elided. // CHECK-NEXT: bitcast // CHECK-NEXT: [[INIT:%.*]] = bitcast - // CHECK-NEXT: [[RET:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[INIT]]) + // CHECK-NEXT: [[RET:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[INIT]]) // CHECK-NEXT: ret i8* [[RET]] @@ -1191,7 +1191,7 @@ id test52(void) { // CHECK-NEXT: store i32 5, i32* [[X]], // CHECK-NEXT: [[T0:%.*]] = load i32* [[X]], // CHECK-NEXT: [[T1:%.*]] = call i8* @test52_helper(i32 [[T0]]) -// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T1]]) +// CHECK-NEXT: [[T2:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T1]]) // CHECK-NEXT: ret i8* [[T2]] } @@ -1292,7 +1292,7 @@ void test56_test(void) { // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds i8* [[T2]], i64 [[T1]] // CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to i8** // CHECK-NEXT: [[T5:%.*]] = call i8* @objc_loadWeakRetained(i8** [[T4]]) -// CHECK-NEXT: [[T6:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T5]]) +// CHECK-NEXT: [[T6:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[T5]]) // CHECK-NEXT: ret i8* [[T6]] // CHECK: define internal i8* @"\01-[Test57 unsafe]"( diff --git a/test/CodeGenObjC/objc-arc-container-subscripting.m b/test/CodeGenObjC/objc-arc-container-subscripting.m index 71339c7085..0961ed1b20 100644 --- a/test/CodeGenObjC/objc-arc-container-subscripting.m +++ b/test/CodeGenObjC/objc-arc-container-subscripting.m @@ -15,6 +15,6 @@ id func() { // CHECK: [[SIX:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[call]]) nounwind // CHECK: [[ARRAY_CASTED:%.*]] = bitcast %0** {{%.*}} to i8** // CHECK: call void @objc_storeStrong(i8** [[ARRAY_CASTED]], i8* null) -// CHECK: [[EIGHT:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[SIX]]) nounwind +// CHECK: [[EIGHT:%.*]] = tail call i8* @objc_autoreleaseReturnValue(i8* [[SIX]]) nounwind // CHECK: ret i8* [[EIGHT]] -- 2.50.1