1; RUN: opt -S -passes=objc-arc < %s | FileCheck %s 2 3declare void @use_pointer(ptr) 4declare ptr @returner() 5declare ptr @llvm.objc.retain(ptr) 6declare ptr @llvm.objc.autoreleaseReturnValue(ptr) 7declare ptr @llvm.objc.retainAutoreleasedReturnValue(ptr) 8 9; Clean up residue left behind after inlining. 10 11; CHECK-LABEL: define void @test0( 12; CHECK: entry: 13; CHECK-NEXT: ret void 14; CHECK-NEXT: } 15define void @test0(ptr %call.i) { 16entry: 17 %0 = tail call ptr @llvm.objc.retain(ptr %call.i) nounwind 18 %1 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %0) nounwind 19 ret void 20} 21 22; Same as test0, but with slightly different use arrangements. 23 24; CHECK-LABEL: define void @test1( 25; CHECK: entry: 26; CHECK-NEXT: ret void 27; CHECK-NEXT: } 28define void @test1(ptr %call.i) { 29entry: 30 %0 = tail call ptr @llvm.objc.retain(ptr %call.i) nounwind 31 %1 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %call.i) nounwind 32 ret void 33} 34 35; Delete a retainRV+autoreleaseRV even if the pointer is used. 36 37; CHECK-LABEL: define void @test24( 38; CHECK-NEXT: entry: 39; CHECK-NEXT: call void @use_pointer(ptr %p) 40; CHECK-NEXT: ret void 41; CHECK-NEXT: } 42define void @test24(ptr %p) { 43entry: 44 call ptr @llvm.objc.autoreleaseReturnValue(ptr %p) nounwind 45 call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %p) nounwind 46 call void @use_pointer(ptr %p) 47 ret void 48} 49 50; Check that we can delete the autoreleaseRV+retainAutoreleasedRV pair even in 51; presence of instructions added by the inliner as part of the return sequence. 52 53; 1) Noop instructions: bitcasts and zero-indices GEPs. 54 55; CHECK-LABEL: define ptr @testNoop( 56; CHECK: entry: 57; CHECK-NEXT: ret ptr %call.i 58; CHECK-NEXT: } 59define ptr @testNoop(ptr %call.i) { 60entry: 61 %0 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %call.i) nounwind 62 %1 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call.i) nounwind 63 ret ptr %call.i 64} 65 66; 2) Lifetime markers. 67 68declare void @llvm.lifetime.start.p0(i64, ptr) 69declare void @llvm.lifetime.end.p0(i64, ptr) 70 71; CHECK-LABEL: define ptr @testLifetime( 72; CHECK: entry: 73; CHECK-NEXT: %obj = alloca i8 74; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 8, ptr %obj) 75; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 8, ptr %obj) 76; CHECK-NEXT: ret ptr %call.i 77; CHECK-NEXT: } 78define ptr @testLifetime(ptr %call.i) { 79entry: 80 %obj = alloca i8 81 call void @llvm.lifetime.start.p0(i64 8, ptr %obj) 82 %0 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %call.i) nounwind 83 call void @llvm.lifetime.end.p0(i64 8, ptr %obj) 84 %1 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call.i) nounwind 85 ret ptr %call.i 86} 87 88; 3) Dynamic alloca markers. 89 90declare ptr @llvm.stacksave() 91declare void @llvm.stackrestore(ptr) 92 93; CHECK-LABEL: define ptr @testStack( 94; CHECK: entry: 95; CHECK-NEXT: %save = tail call ptr @llvm.stacksave.p0() 96; CHECK-NEXT: %obj = alloca i8, i8 %arg 97; CHECK-NEXT: call void @llvm.stackrestore.p0(ptr %save) 98; CHECK-NEXT: ret ptr %call.i 99; CHECK-NEXT: } 100define ptr @testStack(ptr %call.i, i8 %arg) { 101entry: 102 %save = tail call ptr @llvm.stacksave() 103 %obj = alloca i8, i8 %arg 104 %0 = tail call ptr @llvm.objc.autoreleaseReturnValue(ptr %call.i) nounwind 105 call void @llvm.stackrestore(ptr %save) 106 %1 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call.i) nounwind 107 ret ptr %call.i 108} 109