1; RUN: llc -mtriple=x86_64-apple-macosx -verify-machineinstrs -o - %s | FileCheck --check-prefix=CHECK %s 2; RUN: llc -mtriple=x86_64-windows-msvc -verify-machineinstrs -o - %s | FileCheck --check-prefix=WINABI %s 3 4; TODO: support marker generation with GlobalISel 5target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" 6 7declare ptr @foo0(i32) 8declare ptr @foo1() 9 10declare void @llvm.objc.release(ptr) 11declare void @objc_object(ptr) 12 13declare void @foo2(ptr) 14 15declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) 16 17declare ptr @_ZN1SD1Ev(ptr nonnull dereferenceable(1)) 18 19declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) 20 21 22%struct.S = type { i8 } 23 24@g = global ptr null, align 8 25@fptr = global ptr null, align 8 26 27define ptr @rv_marker_1_retain() { 28; CHECK-LABEL: rv_marker_1_retain: 29; CHECK: pushq %rax 30; CHECK-NEXT: .cfi_def_cfa_offset 16 31; CHECK-NEXT: callq _foo1 32; CHECK-NEXT: movq %rax, %rdi 33; CHECK-NEXT: callq _objc_retainAutoreleasedReturnValue 34; CHECK-NEXT: popq %rcx 35; CHECK-NEXT: retq 36; 37; WINABI-LABEL: rv_marker_1_retain: 38; WINABI: callq foo1 39; WINABI-NEXT: movq %rax, %rcx 40; WINABI-NEXT: callq objc_retainAutoreleasedReturnValue 41; WINABI-NEXT: nop 42; 43entry: 44 %call = call ptr @foo1() [ "clang.arc.attachedcall"(ptr @objc_retainAutoreleasedReturnValue) ] 45 ret ptr %call 46} 47 48define ptr @rv_marker_1_unsafeClaim() { 49; CHECK-LABEL: rv_marker_1_unsafeClaim: 50; CHECK: pushq %rax 51; CHECK-NEXT: .cfi_def_cfa_offset 16 52; CHECK-NEXT: callq _foo1 53; CHECK-NEXT: movq %rax, %rdi 54; CHECK-NEXT: callq _objc_unsafeClaimAutoreleasedReturnValue 55; CHECK-NEXT: popq %rcx 56; CHECK-NEXT: retq 57; 58entry: 59 %call = call ptr @foo1() [ "clang.arc.attachedcall"(ptr @objc_unsafeClaimAutoreleasedReturnValue) ] 60 ret ptr %call 61} 62 63define void @rv_marker_2_select(i32 %c) { 64; CHECK-LABEL: rv_marker_2_select: 65; CHECK: pushq %rax 66; CHECK-NEXT: .cfi_def_cfa_offset 16 67; CHECK-NEXT: xorl %eax, %eax 68; CHECK-NEXT: cmpl $1, %edi 69; CHECK-NEXT: adcl $1, %eax 70; CHECK-NEXT: movl %eax, %edi 71; CHECK-NEXT: callq _foo0 72; CHECK-NEXT: movq %rax, %rdi 73; CHECK-NEXT: callq _objc_retainAutoreleasedReturnValue 74; CHECK-NEXT: movq %rax, %rdi 75; CHECK-NEXT: popq %rax 76; CHECK-NEXT: jmp _foo2 77; 78entry: 79 %tobool.not = icmp eq i32 %c, 0 80 %.sink = select i1 %tobool.not, i32 2, i32 1 81 %call1 = call ptr @foo0(i32 %.sink) [ "clang.arc.attachedcall"(ptr @objc_retainAutoreleasedReturnValue) ] 82 tail call void @foo2(ptr %call1) 83 ret void 84} 85 86define void @rv_marker_3() personality ptr @__gxx_personality_v0 { 87; CHECK-LABEL: rv_marker_3 88; CHECK: pushq %r14 89; CHECK-NEXT: .cfi_def_cfa_offset 16 90; CHECK-NEXT: pushq %rbx 91; CHECK-NEXT: .cfi_def_cfa_offset 24 92; CHECK-NEXT: pushq %rax 93; CHECK-NEXT: .cfi_def_cfa_offset 32 94; CHECK-NEXT: .cfi_offset %rbx, -24 95; CHECK-NEXT: .cfi_offset %r14, -16 96; CHECK-NEXT: callq _foo1 97; CHECK-NEXT: movq %rax, %rdi 98; CHECK-NEXT: callq _objc_retainAutoreleasedReturnValue 99; CHECK-NEXT: movq %rax, %rbx 100; CHECK-NEXT: Ltmp0: 101; 102entry: 103 %call = call ptr @foo1() [ "clang.arc.attachedcall"(ptr @objc_retainAutoreleasedReturnValue) ] 104 invoke void @objc_object(ptr %call) #5 105 to label %invoke.cont unwind label %lpad 106 107invoke.cont: ; preds = %entry 108 tail call void @llvm.objc.release(ptr %call) 109 ret void 110 111lpad: ; preds = %entry 112 %0 = landingpad { ptr, i32 } 113 cleanup 114 tail call void @llvm.objc.release(ptr %call) 115 resume { ptr, i32 } %0 116} 117 118define void @rv_marker_4() personality ptr @__gxx_personality_v0 { 119; CHECK-LABEL: rv_marker_4 120; CHECK: pushq %r14 121; CHECK-NEXT: .cfi_def_cfa_offset 16 122; CHECK-NEXT: pushq %rbx 123; CHECK-NEXT: .cfi_def_cfa_offset 24 124; CHECK-NEXT: pushq %rax 125; CHECK-NEXT: .cfi_def_cfa_offset 32 126; CHECK-NEXT: .cfi_offset %rbx, -24 127; CHECK-NEXT: .cfi_offset %r14, -16 128; CHECK-NEXT: Ltmp3: 129; CHECK-NEXT: callq _foo1 130; CHECK-NEXT: movq %rax, %rdi 131; CHECK-NEXT: callq _objc_retainAutoreleasedReturnValue 132; CHECK-NEXT: Ltmp4: 133; 134entry: 135 %s = alloca %struct.S, align 1 136 call void @llvm.lifetime.start.p0(i64 1, ptr nonnull %s) #2 137 %call = invoke ptr @foo1() [ "clang.arc.attachedcall"(ptr @objc_retainAutoreleasedReturnValue) ] 138 to label %invoke.cont unwind label %lpad 139 140invoke.cont: ; preds = %entry 141 invoke void @objc_object(ptr %call) #5 142 to label %invoke.cont2 unwind label %lpad1 143 144invoke.cont2: ; preds = %invoke.cont 145 tail call void @llvm.objc.release(ptr %call) 146 %call3 = call ptr @_ZN1SD1Ev(ptr nonnull dereferenceable(1) %s) 147 call void @llvm.lifetime.end.p0(i64 1, ptr nonnull %s) 148 ret void 149 150lpad: ; preds = %entry 151 %0 = landingpad { ptr, i32 } 152 cleanup 153 br label %ehcleanup 154 155lpad1: ; preds = %invoke.cont 156 %1 = landingpad { ptr, i32 } 157 cleanup 158 tail call void @llvm.objc.release(ptr %call) 159 br label %ehcleanup 160 161ehcleanup: ; preds = %lpad1, %lpad 162 %.pn = phi { ptr, i32 } [ %1, %lpad1 ], [ %0, %lpad ] 163 %call4 = call ptr @_ZN1SD1Ev(ptr nonnull dereferenceable(1) %s) 164 call void @llvm.lifetime.end.p0(i64 1, ptr nonnull %s) 165 resume { ptr, i32 } %.pn 166} 167 168; TODO: This should use "callq *_fptr(%rip)". 169define ptr @rv_marker_5_indirect_call() { 170; CHECK-LABEL: rv_marker_5_indirect_call 171; CHECK: pushq %rbx 172; CHECK-NEXT: .cfi_def_cfa_offset 16 173; CHECK-NEXT: .cfi_offset %rbx, -16 174; CHECK-NEXT: movq _fptr(%rip), %rax 175; CHECK-NEXT: callq *%rax 176; CHECK-NEXT: movq %rax, %rdi 177; CHECK-NEXT: callq _objc_retainAutoreleasedReturnValue 178; CHECK-NEXT: movq %rax, %rbx 179; CHECK-NEXT: movq %rax, %rdi 180; CHECK-NEXT: callq _foo2 181; CHECK-NEXT: movq %rbx, %rax 182; CHECK-NEXT: popq %rbx 183; CHECK-NEXT: retq 184; 185entry: 186 %lv = load ptr, ptr @fptr, align 8 187 %call = call ptr %lv() [ "clang.arc.attachedcall"(ptr @objc_retainAutoreleasedReturnValue) ] 188 tail call void @foo2(ptr %call) 189 ret ptr %call 190} 191 192declare ptr @foo(i64, i64, i64) 193 194define void @rv_marker_multiarg(i64 %a, i64 %b, i64 %c) { 195; CHECK-LABEL: rv_marker_multiarg 196; CHECK: pushq %rax 197; CHECK-NEXT: .cfi_def_cfa_offset 16 198; CHECK-NEXT: movq %rdi, %rax 199; CHECK-NEXT: movq %rdx, %rdi 200; CHECK-NEXT: movq %rax, %rdx 201; CHECK-NEXT: callq _foo 202; CHECK-NEXT: movq %rax, %rdi 203; CHECK-NEXT: callq _objc_retainAutoreleasedReturnValue 204; CHECK-NEXT: popq %rax 205; CHECK-NEXT: retq 206; 207 %r = call ptr @foo(i64 %c, i64 %b, i64 %a) [ "clang.arc.attachedcall"(ptr @objc_retainAutoreleasedReturnValue) ] 208 ret void 209} 210 211define void @test_nonlazybind() { 212; CHECK-LABEL: _test_nonlazybind: 213; CHECK: bb.0: 214; CHECK-NEXT: pushq %rax 215; CHECK-NEXT: .cfi_def_cfa_offset 16 216; CHECK-NEXT: callq *_foo_nonlazybind@GOTPCREL(%rip) 217; CHECK-NEXT: movq %rax, %rdi 218; CHECK-NEXT: callq _objc_retainAutoreleasedReturnValue 219; 220 %call1 = notail call ptr @foo_nonlazybind() [ "clang.arc.attachedcall"(ptr @objc_retainAutoreleasedReturnValue) ] 221 ret void 222} 223 224declare ptr @foo_nonlazybind() nonlazybind 225 226declare ptr @objc_retainAutoreleasedReturnValue(ptr) 227declare ptr @objc_unsafeClaimAutoreleasedReturnValue(ptr) 228declare i32 @__gxx_personality_v0(...) 229 230declare ptr @fn1() 231declare ptr @fn2() 232 233define ptr @rv_marker_block_placement(i1 %c.0) { 234; CHECK-LABEL: _rv_marker_block_placement: 235; CHECK: pushq %rax 236; CHECK-NEXT: .cfi_def_cfa_offset 16 237; CHECK-NEXT: testb $1, %dil 238; CHECK-NEXT: je LBB8_2 239 240; CHECK-NEXT: ## %bb.1: 241; CHECK-NEXT: callq _fn1 242; CHECK-NEXT: movq %rax, %rdi 243; CHECK-NEXT: callq _objc_retainAutoreleasedReturnValue 244; CHECK-NEXT: jmp LBB8_3 245 246; CHECK-NEXT: LBB8_2: 247; CHECK-NEXT: callq _fn2 248; CHECK-NEXT: movq %rax, %rdi 249; CHECK-NEXT: callq _objc_retainAutoreleasedReturnValue 250 251; CHECK-NEXT: LBB8_3: 252; CHECK-NEXT: xorl %eax, %eax 253; CHECK-NEXT: popq %rcx 254; CHECK-NEXT: retq 255; 256entry: 257 br i1 %c.0, label %then, label %else 258 259then: 260 %call.0 = notail call ptr @fn1() [ "clang.arc.attachedcall"(ptr @objc_retainAutoreleasedReturnValue) ] 261 br label %exit 262 263else: 264 %call.1 = notail call ptr @fn2() [ "clang.arc.attachedcall"(ptr @objc_retainAutoreleasedReturnValue) ] 265 br label %exit 266 267exit: 268 ret ptr null 269} 270