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