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