static llvm::Value *emitARCValueOperation(CodeGenFunction &CGF,
llvm::Value *value,
llvm::Constant *&fn,
- StringRef fnName) {
+ StringRef fnName,
+ bool isTailCall = false) {
if (isa<llvm::ConstantPointerNull>(value)) return value;
if (!fn) {
// 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);
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.
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.
// 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; };
// 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()
// 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]]
}
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]]
}
// 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:]"
// 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;
// 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]]
// 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]]
}
// 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]"(
// 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]]