; RUN: opt -S -objc-arc < %s | FileCheck %s declare void @use_pointer(i8*) declare i8* @returner() declare i8* @llvm.objc.retain(i8*) declare i8* @llvm.objc.autoreleaseReturnValue(i8*) declare i8* @llvm.objc.retainAutoreleasedReturnValue(i8*) ; Clean up residue left behind after inlining. ; CHECK-LABEL: define void @test0( ; CHECK: entry: ; CHECK-NEXT: ret void ; CHECK-NEXT: } define void @test0(i8* %call.i) { entry: %0 = tail call i8* @llvm.objc.retain(i8* %call.i) nounwind %1 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %0) nounwind ret void } ; Same as test0, but with slightly different use arrangements. ; CHECK-LABEL: define void @test1( ; CHECK: entry: ; CHECK-NEXT: ret void ; CHECK-NEXT: } define void @test1(i8* %call.i) { entry: %0 = tail call i8* @llvm.objc.retain(i8* %call.i) nounwind %1 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %call.i) nounwind ret void } ; Delete a retainRV+autoreleaseRV even if the pointer is used. ; CHECK-LABEL: define void @test24( ; CHECK-NEXT: entry: ; CHECK-NEXT: call void @use_pointer(i8* %p) ; CHECK-NEXT: ret void ; CHECK-NEXT: } define void @test24(i8* %p) { entry: call i8* @llvm.objc.autoreleaseReturnValue(i8* %p) nounwind call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %p) nounwind call void @use_pointer(i8* %p) ret void } ; Check that we can delete the autoreleaseRV+retainAutoreleasedRV pair even in ; presence of instructions added by the inliner as part of the return sequence. ; 1) Noop instructions: bitcasts and zero-indices GEPs. ; CHECK-LABEL: define i8* @testNoop( ; CHECK: entry: ; CHECK-NEXT: %noop0 = bitcast i8* %call.i to i64* ; CHECK-NEXT: %noop1 = getelementptr i8, i8* %call.i, i32 0 ; CHECK-NEXT: ret i8* %call.i ; CHECK-NEXT: } define i8* @testNoop(i8* %call.i) { entry: %0 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %call.i) nounwind %noop0 = bitcast i8* %call.i to i64* %noop1 = getelementptr i8, i8* %call.i, i32 0 %1 = tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call.i) nounwind ret i8* %call.i } ; 2) Lifetime markers. declare void @llvm.lifetime.start.p0i8(i64, i8*) declare void @llvm.lifetime.end.p0i8(i64, i8*) ; CHECK-LABEL: define i8* @testLifetime( ; CHECK: entry: ; CHECK-NEXT: %obj = alloca i8 ; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* %obj) ; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* %obj) ; CHECK-NEXT: ret i8* %call.i ; CHECK-NEXT: } define i8* @testLifetime(i8* %call.i) { entry: %obj = alloca i8 call void @llvm.lifetime.start.p0i8(i64 8, i8* %obj) %0 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %call.i) nounwind call void @llvm.lifetime.end.p0i8(i64 8, i8* %obj) %1 = tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call.i) nounwind ret i8* %call.i } ; 3) Dynamic alloca markers. declare i8* @llvm.stacksave() declare void @llvm.stackrestore(i8*) ; CHECK-LABEL: define i8* @testStack( ; CHECK: entry: ; CHECK-NEXT: %save = tail call i8* @llvm.stacksave() ; CHECK-NEXT: %obj = alloca i8, i8 %arg ; CHECK-NEXT: call void @llvm.stackrestore(i8* %save) ; CHECK-NEXT: ret i8* %call.i ; CHECK-NEXT: } define i8* @testStack(i8* %call.i, i8 %arg) { entry: %save = tail call i8* @llvm.stacksave() %obj = alloca i8, i8 %arg %0 = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* %call.i) nounwind call void @llvm.stackrestore(i8* %save) %1 = tail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* %call.i) nounwind ret i8* %call.i }