1; RUN: llc < %s -mtriple=x86_64-apple-darwin -disable-fp-elim | FileCheck %s
2;
3; Note: Print verbose stackmaps using -debug-only=stackmaps.
4
5; CHECK-LABEL:  .section  __LLVM_STACKMAPS,__llvm_stackmaps
6; CHECK-NEXT:  __LLVM_StackMaps:
7; CHECK-NEXT:   .long   0
8; Num LargeConstants
9; CHECK-NEXT:   .long   1
10; CHECK-NEXT:   .quad   4294967296
11; Num Callsites
12; CHECK-NEXT:   .long   11
13
14; Constant arguments
15;
16; CHECK-NEXT:   .long   1
17; CHECK-NEXT:   .long   L{{.*}}-_constantargs
18; CHECK-NEXT:   .short  0
19; CHECK-NEXT:   .short  4
20; SmallConstant
21; CHECK-NEXT:   .byte   4
22; CHECK-NEXT:   .byte   8
23; CHECK-NEXT:   .short  0
24; CHECK-NEXT:   .long   65535
25; SmallConstant
26; CHECK-NEXT:   .byte   4
27; CHECK-NEXT:   .byte   8
28; CHECK-NEXT:   .short  0
29; CHECK-NEXT:   .long   65536
30; SmallConstant
31; CHECK-NEXT:   .byte   4
32; CHECK-NEXT:   .byte   8
33; CHECK-NEXT:   .short  0
34; CHECK-NEXT:   .long   -1
35; LargeConstant at index 0
36; CHECK-NEXT:   .byte   5
37; CHECK-NEXT:   .byte   8
38; CHECK-NEXT:   .short  0
39; CHECK-NEXT:   .long   0
40
41define void @constantargs() {
42entry:
43  %0 = inttoptr i64 12345 to i8*
44  tail call void (i32, i32, i8*, i32, ...)* @llvm.experimental.patchpoint.void(i32 1, i32 15, i8* %0, i32 0, i64 65535, i64 65536, i64 4294967295, i64 4294967296)
45  ret void
46}
47
48; Inline OSR Exit
49;
50; CHECK-NEXT:   .long   3
51; CHECK-NEXT:   .long   L{{.*}}-_osrinline
52; CHECK-NEXT:   .short  0
53; CHECK-NEXT:   .short  2
54; CHECK-NEXT:   .byte   1
55; CHECK-NEXT:   .byte   8
56; CHECK-NEXT:   .short  {{[0-9]+}}
57; CHECK-NEXT:   .long   0
58; CHECK-NEXT:   .byte   1
59; CHECK-NEXT:   .byte   8
60; CHECK-NEXT:   .short  {{[0-9]+}}
61; CHECK-NEXT:   .long  0
62define void @osrinline(i64 %a, i64 %b) {
63entry:
64  ; Runtime void->void call.
65  call void inttoptr (i64 -559038737 to void ()*)()
66  ; Followed by inline OSR patchpoint with 12-byte shadow and 2 live vars.
67  call void (i32, i32, ...)* @llvm.experimental.stackmap(i32 3, i32 12, i64 %a, i64 %b)
68  ret void
69}
70
71; Cold OSR Exit
72;
73; 2 live variables in register.
74;
75; CHECK-NEXT:   .long  4
76; CHECK-NEXT:   .long   L{{.*}}-_osrcold
77; CHECK-NEXT:   .short  0
78; CHECK-NEXT:   .short  2
79; CHECK-NEXT:   .byte   1
80; CHECK-NEXT:   .byte   8
81; CHECK-NEXT:   .short  {{[0-9]+}}
82; CHECK-NEXT:   .long   0
83; CHECK-NEXT:   .byte   1
84; CHECK-NEXT:   .byte   8
85; CHECK-NEXT:   .short  {{[0-9]+}}
86; CHECK-NEXT:   .long  0
87define void @osrcold(i64 %a, i64 %b) {
88entry:
89  %test = icmp slt i64 %a, %b
90  br i1 %test, label %ret, label %cold
91cold:
92  ; OSR patchpoint with 12-byte nop-slide and 2 live vars.
93  %thunk = inttoptr i64 -559038737 to i8*
94  call void (i32, i32, i8*, i32, ...)* @llvm.experimental.patchpoint.void(i32 4, i32 15, i8* %thunk, i32 0, i64 %a, i64 %b)
95  unreachable
96ret:
97  ret void
98}
99
100; Property Read
101; CHECK-NEXT:  .long  5
102; CHECK-NEXT:   .long   L{{.*}}-_propertyRead
103; CHECK-NEXT:  .short  0
104; CHECK-NEXT:  .short  0
105;
106; FIXME: There are currently no stackmap entries. After moving to
107; AnyRegCC, we will have entries for the object and return value.
108define i64 @propertyRead(i64* %obj) {
109entry:
110  %resolveRead = inttoptr i64 -559038737 to i8*
111  %result = call i64 (i32, i32, i8*, i32, ...)* @llvm.experimental.patchpoint.i64(i32 5, i32 15, i8* %resolveRead, i32 1, i64* %obj)
112  %add = add i64 %result, 3
113  ret i64 %add
114}
115
116; Property Write
117; CHECK-NEXT:  .long  6
118; CHECK-NEXT:   .long   L{{.*}}-_propertyWrite
119; CHECK-NEXT:  .short  0
120; CHECK-NEXT:  .short  0
121;
122; FIXME: There are currently no stackmap entries. After moving to
123; AnyRegCC, we will have entries for the object and return value.
124define void @propertyWrite(i64 %dummy1, i64* %obj, i64 %dummy2, i64 %a) {
125entry:
126  %resolveWrite = inttoptr i64 -559038737 to i8*
127  call void (i32, i32, i8*, i32, ...)* @llvm.experimental.patchpoint.void(i32 6, i32 15, i8* %resolveWrite, i32 2, i64* %obj, i64 %a)
128  ret void
129}
130
131; Void JS Call
132;
133; 2 live variables in registers.
134;
135; CHECK-NEXT:   .long  7
136; CHECK-NEXT:   .long   L{{.*}}-_jsVoidCall
137; CHECK-NEXT:   .short  0
138; CHECK-NEXT:   .short  2
139; CHECK-NEXT:   .byte   1
140; CHECK-NEXT:   .byte   8
141; CHECK-NEXT:   .short  {{[0-9]+}}
142; CHECK-NEXT:   .long   0
143; CHECK-NEXT:   .byte   1
144; CHECK-NEXT:   .byte   8
145; CHECK-NEXT:   .short  {{[0-9]+}}
146; CHECK-NEXT:   .long   0
147define void @jsVoidCall(i64 %dummy1, i64* %obj, i64 %arg, i64 %l1, i64 %l2) {
148entry:
149  %resolveCall = inttoptr i64 -559038737 to i8*
150  call void (i32, i32, i8*, i32, ...)* @llvm.experimental.patchpoint.void(i32 7, i32 15, i8* %resolveCall, i32 2, i64* %obj, i64 %arg, i64 %l1, i64 %l2)
151  ret void
152}
153
154; i64 JS Call
155;
156; 2 live variables in registers.
157;
158; CHECK:        .long  8
159; CHECK-NEXT:   .long   L{{.*}}-_jsIntCall
160; CHECK-NEXT:   .short  0
161; CHECK-NEXT:   .short  2
162; CHECK-NEXT:   .byte   1
163; CHECK-NEXT:   .byte   8
164; CHECK-NEXT:   .short  {{[0-9]+}}
165; CHECK-NEXT:   .long   0
166; CHECK-NEXT:   .byte   1
167; CHECK-NEXT:   .byte   8
168; CHECK-NEXT:   .short  {{[0-9]+}}
169; CHECK-NEXT:   .long   0
170define i64 @jsIntCall(i64 %dummy1, i64* %obj, i64 %arg, i64 %l1, i64 %l2) {
171entry:
172  %resolveCall = inttoptr i64 -559038737 to i8*
173  %result = call i64 (i32, i32, i8*, i32, ...)* @llvm.experimental.patchpoint.i64(i32 8, i32 15, i8* %resolveCall, i32 2, i64* %obj, i64 %arg, i64 %l1, i64 %l2)
174  %add = add i64 %result, 3
175  ret i64 %add
176}
177
178; Spilled stack map values.
179;
180; Verify 17 stack map entries.
181;
182; CHECK:      .long 11
183; CHECK-NEXT: .long L{{.*}}-_spilledValue
184; CHECK-NEXT: .short 0
185; CHECK-NEXT: .short 17
186;
187; Check that at least one is a spilled entry from RBP.
188; Location: Indirect RBP + ...
189; CHECK:      .byte 3
190; CHECK-NEXT: .byte 8
191; CHECK-NEXT: .short 6
192define void @spilledValue(i64 %arg0, i64 %arg1, i64 %arg2, i64 %arg3, i64 %arg4, i64 %l0, i64 %l1, i64 %l2, i64 %l3, i64 %l4, i64 %l5, i64 %l6, i64 %l7, i64 %l8, i64 %l9, i64 %l10, i64 %l11, i64 %l12, i64 %l13, i64 %l14, i64 %l15, i64 %l16) {
193entry:
194  call void (i32, i32, i8*, i32, ...)* @llvm.experimental.patchpoint.void(i32 11, i32 15, i8* null, i32 5, i64 %arg0, i64 %arg1, i64 %arg2, i64 %arg3, i64 %arg4, i64 %l0, i64 %l1, i64 %l2, i64 %l3, i64 %l4, i64 %l5, i64 %l6, i64 %l7, i64 %l8, i64 %l9, i64 %l10, i64 %l11, i64 %l12, i64 %l13, i64 %l14, i64 %l15, i64 %l16)
195  ret void
196}
197
198; Spilled stack map values.
199;
200; Verify 17 stack map entries.
201;
202; CHECK:       .long 12
203; CHECK-LABEL: .long L{{.*}}-_spilledStackMapValue
204; CHECK-NEXT:  .short 0
205; CHECK-NEXT:  .short 17
206;
207; Check that at least one is a spilled entry from RBP.
208; Location: Indirect RBP + ...
209; CHECK:      .byte 3
210; CHECK-NEXT: .byte 8
211; CHECK-NEXT: .short 6
212define webkit_jscc void @spilledStackMapValue(i64 %l0, i64 %l1, i64 %l2, i64 %l3, i64 %l4, i64 %l5, i64 %l6, i64 %l7, i64 %l8, i64 %l9, i64 %l10, i64 %l11, i64 %l12, i64 %l13, i64 %l14, i64 %l15, i64 %l16) {
213entry:
214  call void (i32, i32, ...)* @llvm.experimental.stackmap(i32 12, i32 15, i64 %l0, i64 %l1, i64 %l2, i64 %l3, i64 %l4, i64 %l5, i64 %l6, i64 %l7, i64 %l8, i64 %l9, i64 %l10, i64 %l11, i64 %l12, i64 %l13, i64 %l14, i64 %l15, i64 %l16)
215  ret void
216}
217
218; Spill a subregister stackmap operand.
219;
220; CHECK:       .long 13
221; CHECK-LABEL: .long L{{.*}}-_spillSubReg
222; CHECK-NEXT:  .short 0
223; 4 locations
224; CHECK-NEXT:  .short 1
225;
226; Check that the subregister operand is a 4-byte spill.
227; Location: Indirect, 4-byte, RBP + ...
228; CHECK:      .byte 3
229; CHECK-NEXT: .byte 4
230; CHECK-NEXT: .short 6
231define void @spillSubReg(i64 %arg) #0 {
232bb:
233  br i1 undef, label %bb1, label %bb2
234
235bb1:
236  unreachable
237
238bb2:
239  %tmp = load i64* inttoptr (i64 140685446136880 to i64*)
240  br i1 undef, label %bb16, label %bb17
241
242bb16:
243  unreachable
244
245bb17:
246  %tmp32 = trunc i64 %tmp to i32
247  br i1 undef, label %bb60, label %bb61
248
249bb60:
250  tail call void asm sideeffect "nop", "~{ax},~{bx},~{cx},~{dx},~{bp},~{si},~{di},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15}"() nounwind
251  tail call void (i32, i32, ...)* @llvm.experimental.stackmap(i32 13, i32 5, i32 %tmp32)
252  unreachable
253
254bb61:
255  unreachable
256}
257
258; Map a single byte subregister. There is no DWARF register number, so
259; we expect the register to be encoded with the proper size and spill offset. We don't know which
260;
261; CHECK:       .long 14
262; CHECK-LABEL: .long L{{.*}}-_subRegOffset
263; CHECK-NEXT:  .short 0
264; 2 locations
265; CHECK-NEXT:  .short 2
266;
267; Check that the subregister operands are 1-byte spills.
268; Location 0: Register, 4-byte, AL
269; CHECK-NEXT: .byte 1
270; CHECK-NEXT: .byte 1
271; CHECK-NEXT: .short 0
272; CHECK-NEXT: .long 0
273;
274; Location 1: Register, 4-byte, BL
275; CHECK-NEXT: .byte 1
276; CHECK-NEXT: .byte 1
277; CHECK-NEXT: .short 3
278; CHECK-NEXT: .long 0
279define void @subRegOffset(i16 %arg) {
280  %v = mul i16 %arg, 5
281  %a0 = trunc i16 %v to i8
282  tail call void asm sideeffect "nop", "~{bx}"() nounwind
283  %arghi = lshr i16 %v, 8
284  %a1 = trunc i16 %arghi to i8
285  tail call void asm sideeffect "nop", "~{cx},~{dx},~{bp},~{si},~{di},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15}"() nounwind
286  tail call void (i32, i32, ...)* @llvm.experimental.stackmap(i32 14, i32 5, i8 %a0, i8 %a1)
287  ret void
288}
289
290declare void @llvm.experimental.stackmap(i32, i32, ...)
291declare void @llvm.experimental.patchpoint.void(i32, i32, i8*, i32, ...)
292declare i64 @llvm.experimental.patchpoint.i64(i32, i32, i8*, i32, ...)
293