1; RUN: llc -mtriple=arm64-apple-darwin -mattr=+reserve-x18                             < %s | FileCheck %s
2; RUN: llc -mtriple=arm64-apple-darwin -mattr=+reserve-x18 -fast-isel -fast-isel-abort=1 < %s | FileCheck %s
3;
4; Note: Print verbose stackmaps using -debug-only=stackmaps.
5
6; We are not getting the correct stack alignment when cross compiling for arm64.
7; So specify a datalayout here.
8target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
9
10; CHECK-LABEL:  .section  __LLVM_STACKMAPS,__llvm_stackmaps
11; CHECK-NEXT:  __LLVM_StackMaps:
12; Header
13; CHECK-NEXT:   .byte 3
14; CHECK-NEXT:   .byte 0
15; CHECK-NEXT:   .short 0
16; Num Functions
17; CHECK-NEXT:   .long 12
18; Num LargeConstants
19; CHECK-NEXT:   .long 3
20; Num Callsites
21; CHECK-NEXT:   .long 12
22
23; Functions and stack size
24; CHECK-NEXT:   .quad _constantargs
25; CHECK-NEXT:   .quad 16
26; CHECK-NEXT:   .quad 1
27; CHECK-NEXT:   .quad _osrinline
28; CHECK-NEXT:   .quad 32
29; CHECK-NEXT:   .quad 1
30; CHECK-NEXT:   .quad _osrcold
31; CHECK-NEXT:   .quad 16
32; CHECK-NEXT:   .quad 1
33; CHECK-NEXT:   .quad _propertyRead
34; CHECK-NEXT:   .quad 16
35; CHECK-NEXT:   .quad 1
36; CHECK-NEXT:   .quad _propertyWrite
37; CHECK-NEXT:   .quad 16
38; CHECK-NEXT:   .quad 1
39; CHECK-NEXT:   .quad _jsVoidCall
40; CHECK-NEXT:   .quad 16
41; CHECK-NEXT:   .quad 1
42; CHECK-NEXT:   .quad _jsIntCall
43; CHECK-NEXT:   .quad 16
44; CHECK-NEXT:   .quad 1
45; CHECK-NEXT:   .quad _spilledValue
46; CHECK-NEXT:   .quad 160
47; CHECK-NEXT:   .quad 1
48; CHECK-NEXT:   .quad _spilledStackMapValue
49; CHECK-NEXT:   .quad 128
50; CHECK-NEXT:   .quad 1
51; CHECK-NEXT:   .quad _liveConstant
52; CHECK-NEXT:   .quad 16
53; CHECK-NEXT:   .quad 1
54; CHECK-NEXT:   .quad _clobberLR
55; CHECK-NEXT:   .quad 112
56; CHECK-NEXT:   .quad 1
57; CHECK-NEXT:   .quad _floats
58; CHECK-NEXT:   .quad 32
59; CHECK-NEXT:   .quad 1
60
61; Num LargeConstants
62; CHECK-NEXT:   .quad   4294967295
63; CHECK-NEXT:   .quad   4294967296
64; CHECK-NEXT:   .quad   4294967297
65
66; Constant arguments
67;
68; CHECK-NEXT:   .quad   1
69; CHECK-NEXT:   .long   L{{.*}}-_constantargs
70; CHECK-NEXT:   .short  0
71; CHECK-NEXT:   .short  6
72; SmallConstant
73; CHECK-NEXT:   .byte   4
74; CHECK-NEXT:   .byte   0
75; CHECK-NEXT:   .short  8
76; CHECK-NEXT:   .short  0
77; CHECK-NEXT:   .short  0
78; CHECK-NEXT:   .long   65535
79; SmallConstant
80; CHECK-NEXT:   .byte   4
81; CHECK-NEXT:   .byte   0
82; CHECK-NEXT:   .short  8
83; CHECK-NEXT:   .short  0
84; CHECK-NEXT:   .short  0
85; CHECK-NEXT:   .long   65536
86; LargeConstant at index 0
87; CHECK-NEXT:   .byte   5
88; CHECK-NEXT:   .byte   0
89; CHECK-NEXT:   .short  8
90; CHECK-NEXT:   .short  0
91; CHECK-NEXT:   .short  0
92; CHECK-NEXT:   .long   0
93; LargeConstant at index 1
94; CHECK-NEXT:   .byte   5
95; CHECK-NEXT:   .byte   0
96; CHECK-NEXT:   .short  8
97; CHECK-NEXT:   .short  0
98; CHECK-NEXT:   .short  0
99; CHECK-NEXT:   .long   1
100; SmallConstant
101; CHECK-NEXT:   .byte   4
102; CHECK-NEXT:   .byte   0
103; CHECK-NEXT:   .short  8
104; CHECK-NEXT:   .short  0
105; CHECK-NEXT:   .short  0
106; CHECK-NEXT:   .long   66
107; LargeConstant at index 2
108; CHECK-NEXT:   .byte   5
109; CHECK-NEXT:   .byte   0
110; CHECK-NEXT:   .short  8
111; CHECK-NEXT:   .short  0
112; CHECK-NEXT:   .short  0
113; CHECK-NEXT:   .long   2
114
115define void @constantargs() {
116entry:
117  %0 = inttoptr i64 244837814094590 to i8*
118  tail call void (i64, i32, i8*, i32, ...) @llvm.experimental.patchpoint.void(i64 1, i32 20, i8* %0, i32 0, i64 65535, i64 65536, i64 4294967295, i64 4294967296, i128 66, i128 4294967297)
119  ret void
120}
121
122; Inline OSR Exit
123;
124; CHECK-LABEL:  .long   L{{.*}}-_osrinline
125; CHECK-NEXT:   .short  0
126; CHECK-NEXT:   .short  2
127; CHECK-NEXT:   .byte   1
128; CHECK-NEXT:   .byte   0
129; CHECK-NEXT:   .short  8
130; CHECK-NEXT:   .short  {{[0-9]+}}
131; CHECK-NEXT:   .short  0
132; CHECK-NEXT:   .long   0
133; CHECK-NEXT:   .byte   1
134; CHECK-NEXT:   .byte   0
135; CHECK-NEXT:   .short  8
136; CHECK-NEXT:   .short  {{[0-9]+}}
137; CHECK-NEXT:   .short  0
138; CHECK-NEXT:   .long  0
139define void @osrinline(i64 %a, i64 %b) {
140entry:
141  ; Runtime void->void call.
142  call void inttoptr (i64 244837814094590 to void ()*)()
143  ; Followed by inline OSR patchpoint with 12-byte shadow and 2 live vars.
144  call void (i64, i32, ...) @llvm.experimental.stackmap(i64 3, i32 12, i64 %a, i64 %b)
145  ret void
146}
147
148; Cold OSR Exit
149;
150; 2 live variables in register.
151;
152; CHECK-LABEL:  .long   L{{.*}}-_osrcold
153; CHECK-NEXT:   .short  0
154; CHECK-NEXT:   .short  2
155; CHECK-NEXT:   .byte   1
156; CHECK-NEXT:   .byte   0
157; CHECK-NEXT:   .short  8
158; CHECK-NEXT:   .short  {{[0-9]+}}
159; CHECK-NEXT:   .short  0
160; CHECK-NEXT:   .long   0
161; CHECK-NEXT:   .byte   1
162; CHECK-NEXT:   .byte   0
163; CHECK-NEXT:   .short  8
164; CHECK-NEXT:   .short  {{[0-9]+}}
165; CHECK-NEXT:   .short  0
166; CHECK-NEXT:   .long  0
167define void @osrcold(i64 %a, i64 %b) {
168entry:
169  %test = icmp slt i64 %a, %b
170  br i1 %test, label %ret, label %cold
171cold:
172  ; OSR patchpoint with 12-byte nop-slide and 2 live vars.
173  %thunk = inttoptr i64 244837814094590 to i8*
174  call void (i64, i32, i8*, i32, ...) @llvm.experimental.patchpoint.void(i64 4, i32 20, i8* %thunk, i32 0, i64 %a, i64 %b)
175  unreachable
176ret:
177  ret void
178}
179
180; Property Read
181; CHECK-LABEL:  .long   L{{.*}}-_propertyRead
182; CHECK-NEXT:   .short  0
183; CHECK-NEXT:   .short  0
184;
185; FIXME: There are currently no stackmap entries. After moving to
186; AnyRegCC, we will have entries for the object and return value.
187define i64 @propertyRead(i64* %obj) {
188entry:
189  %resolveRead = inttoptr i64 244837814094590 to i8*
190  %result = call i64 (i64, i32, i8*, i32, ...) @llvm.experimental.patchpoint.i64(i64 5, i32 20, i8* %resolveRead, i32 1, i64* %obj)
191  %add = add i64 %result, 3
192  ret i64 %add
193}
194
195; Property Write
196; CHECK-LABEL:  .long   L{{.*}}-_propertyWrite
197; CHECK-NEXT:   .short  0
198; CHECK-NEXT:   .short  2
199; CHECK-NEXT:   .byte   1
200; CHECK-NEXT:   .byte   0
201; CHECK-NEXT:   .short  8
202; CHECK-NEXT:   .short  {{[0-9]+}}
203; CHECK-NEXT:   .short  0
204; CHECK-NEXT:   .long   0
205; CHECK-NEXT:   .byte   1
206; CHECK-NEXT:   .byte   0
207; CHECK-NEXT:   .short  8
208; CHECK-NEXT:   .short  {{[0-9]+}}
209; CHECK-NEXT:   .short  0
210; CHECK-NEXT:   .long   0
211define void @propertyWrite(i64 %dummy1, i64* %obj, i64 %dummy2, i64 %a) {
212entry:
213  %resolveWrite = inttoptr i64 244837814094590 to i8*
214  call anyregcc void (i64, i32, i8*, i32, ...) @llvm.experimental.patchpoint.void(i64 6, i32 20, i8* %resolveWrite, i32 2, i64* %obj, i64 %a)
215  ret void
216}
217
218; Void JS Call
219;
220; 2 live variables in registers.
221;
222; CHECK-LABEL:  .long   L{{.*}}-_jsVoidCall
223; CHECK-NEXT:   .short  0
224; CHECK-NEXT:   .short  2
225; CHECK-NEXT:   .byte   1
226; CHECK-NEXT:   .byte   0
227; CHECK-NEXT:   .short  8
228; CHECK-NEXT:   .short  {{[0-9]+}}
229; CHECK-NEXT:   .short  0
230; CHECK-NEXT:   .long   0
231; CHECK-NEXT:   .byte   1
232; CHECK-NEXT:   .byte   0
233; CHECK-NEXT:   .short  8
234; CHECK-NEXT:   .short  {{[0-9]+}}
235; CHECK-NEXT:   .short  0
236; CHECK-NEXT:   .long   0
237define void @jsVoidCall(i64 %dummy1, i64* %obj, i64 %arg, i64 %l1, i64 %l2) {
238entry:
239  %resolveCall = inttoptr i64 244837814094590 to i8*
240  call void (i64, i32, i8*, i32, ...) @llvm.experimental.patchpoint.void(i64 7, i32 20, i8* %resolveCall, i32 2, i64* %obj, i64 %arg, i64 %l1, i64 %l2)
241  ret void
242}
243
244; i64 JS Call
245;
246; 2 live variables in registers.
247;
248; CHECK-LABEL:  .long   L{{.*}}-_jsIntCall
249; CHECK-NEXT:   .short  0
250; CHECK-NEXT:   .short  2
251; CHECK-NEXT:   .byte   1
252; CHECK-NEXT:   .byte   0
253; CHECK-NEXT:   .short  8
254; CHECK-NEXT:   .short  {{[0-9]+}}
255; CHECK-NEXT:   .short  0
256; CHECK-NEXT:   .long   0
257; CHECK-NEXT:   .byte   1
258; CHECK-NEXT:   .byte   0
259; CHECK-NEXT:   .short  8
260; CHECK-NEXT:   .short  {{[0-9]+}}
261; CHECK-NEXT:   .short  0
262; CHECK-NEXT:   .long   0
263define i64 @jsIntCall(i64 %dummy1, i64* %obj, i64 %arg, i64 %l1, i64 %l2) {
264entry:
265  %resolveCall = inttoptr i64 244837814094590 to i8*
266  %result = call i64 (i64, i32, i8*, i32, ...) @llvm.experimental.patchpoint.i64(i64 8, i32 20, i8* %resolveCall, i32 2, i64* %obj, i64 %arg, i64 %l1, i64 %l2)
267  %add = add i64 %result, 3
268  ret i64 %add
269}
270
271; Spilled stack map values.
272;
273; Verify 28 stack map entries.
274;
275; CHECK-LABEL:  .long L{{.*}}-_spilledValue
276; CHECK-NEXT:   .short 0
277; CHECK-NEXT:   .short 28
278;
279; Check that at least one is a spilled entry from RBP.
280; Location: Indirect FP + ...
281; CHECK:        .byte 3
282; CHECK-NEXT:   .byte 0
283; CHECK-NEXT:   .short
284; CHECK-NEXT:   .short 29
285; CHECK-NEXT:   .short  0
286; CHECK-NEXT:   .long
287define 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, i64 %l17, i64 %l18, i64 %l19, i64 %l20, i64 %l21, i64 %l22, i64 %l23, i64 %l24, i64 %l25, i64 %l26, i64 %l27) {
288entry:
289  call void (i64, i32, i8*, i32, ...) @llvm.experimental.patchpoint.void(i64 11, i32 20, 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, i64 %l17, i64 %l18, i64 %l19, i64 %l20, i64 %l21, i64 %l22, i64 %l23, i64 %l24, i64 %l25, i64 %l26, i64 %l27)
290  ret void
291}
292
293; Spilled stack map values.
294;
295; Verify 23 stack map entries.
296;
297; CHECK-LABEL:  .long L{{.*}}-_spilledStackMapValue
298; CHECK-NEXT:   .short 0
299; CHECK-NEXT:   .short 30
300;
301; Check that at least one is a spilled entry from RBP.
302; Location: Indirect FP + ...
303; CHECK:        .byte 3
304; CHECK-NEXT:   .byte 0
305; CHECK-NEXT:   .short
306; CHECK-NEXT:   .short 29
307; CHECK-NEXT:   .short  0
308; CHECK-NEXT:   .long
309define 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, i64 %l17, i64 %l18, i64 %l19, i64 %l20, i64 %l21, i64 %l22, i64 %l23, i64 %l24, i64 %l25, i64 %l26, i64 %l27, i64 %l28, i64 %l29) {
310entry:
311  call void (i64, i32, ...) @llvm.experimental.stackmap(i64 12, i32 16, 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, i64 %l17, i64 %l18, i64 %l19, i64 %l20, i64 %l21, i64 %l22, i64 %l23, i64 %l24, i64 %l25, i64 %l26, i64 %l27, i64 %l28, i64 %l29)
312  ret void
313}
314
315
316; Map a constant value.
317;
318; CHECK-LABEL:  .long L{{.*}}-_liveConstant
319; CHECK-NEXT:   .short 0
320; 1 location
321; CHECK-NEXT:   .short 1
322; Loc 0: SmallConstant
323; CHECK-NEXT:   .byte   4
324; CHECK-NEXT:   .byte   0
325; CHECK-NEXT:   .short  8
326; CHECK-NEXT:   .short  0
327; CHECK-NEXT:   .short  0
328; CHECK-NEXT:   .long   33
329
330define void @liveConstant() {
331  tail call void (i64, i32, ...) @llvm.experimental.stackmap(i64 15, i32 8, i32 33)
332  ret void
333}
334
335; Map a value when LR is the only free register.
336;
337; CHECK-LABEL:  .long L{{.*}}-_clobberLR
338; CHECK-NEXT:   .short 0
339; 1 location
340; CHECK-NEXT:   .short 1
341; Loc 0: Indirect FP (r29) - offset
342; CHECK-NEXT:   .byte   3
343; CHECK-NEXT:   .byte   0
344; CHECK-NEXT:   .short  4
345; CHECK-NEXT:   .short  29
346; CHECK-NEXT:   .short  0
347; CHECK-NEXT:   .long   -{{[0-9]+}}
348define void @clobberLR(i32 %a) {
349  tail call void asm sideeffect "nop", "~{x0},~{x1},~{x2},~{x3},~{x4},~{x5},~{x6},~{x7},~{x8},~{x9},~{x10},~{x11},~{x12},~{x13},~{x14},~{x15},~{x16},~{x17},~{x18},~{x19},~{x20},~{x21},~{x22},~{x23},~{x24},~{x25},~{x26},~{x27},~{x28},~{x29},~{x31}"() nounwind
350  tail call void (i64, i32, ...) @llvm.experimental.stackmap(i64 16, i32 8, i32 %a)
351  ret void
352}
353
354; CHECK-LABEL:  .long L{{.*}}-_floats
355; CHECK-NEXT:   .short 0
356; Num Locations
357; CHECK-NEXT:   .short 6
358; Loc 0: constant float stored to FP register
359; CHECK-NEXT:   .byte   1
360; CHECK-NEXT:   .byte   0
361; CHECK-NEXT:   .short  4
362; CHECK-NEXT:   .short  {{.*}}
363; CHECK-NEXT:   .short  0
364; CHECK-NEXT:   .long   0
365; Loc 0: constant double stored to FP register
366; CHECK-NEXT:   .byte   1
367; CHECK-NEXT:   .byte   0
368; CHECK-NEXT:   .short  8
369; CHECK-NEXT:   .short  {{.*}}
370; CHECK-NEXT:   .short  0
371; CHECK-NEXT:   .long   0
372; Loc 1: float value in FP register
373; CHECK-NEXT:   .byte   1
374; CHECK-NEXT:   .byte   0
375; CHECK-NEXT:   .short  4
376; CHECK-NEXT:   .short  {{.*}}
377; CHECK-NEXT:   .short  0
378; CHECK-NEXT:   .long   0
379; Loc 2: double value in FP register
380; CHECK-NEXT:   .byte   1
381; CHECK-NEXT:   .byte   0
382; CHECK-NEXT:   .short  8
383; CHECK-NEXT:   .short  {{.*}}
384; CHECK-NEXT:   .short  0
385; CHECK-NEXT:   .long   0
386; Loc 3: float on stack
387; CHECK-NEXT:   .byte   2
388; CHECK-NEXT:   .byte   0
389; CHECK-NEXT:   .short  8
390; CHECK-NEXT:   .short  {{.*}}
391; CHECK-NEXT:   .short  0
392; CHECK-NEXT:   .long   -{{.*}}
393; Loc 4: double on stack
394; CHECK-NEXT:   .byte   2
395; CHECK-NEXT:   .byte   0
396; CHECK-NEXT:   .short  8
397; CHECK-NEXT:   .short  {{.*}}
398; CHECK-NEXT:   .short  0
399; CHECK-NEXT:   .long   -{{.*}}
400define void @floats(float %f, double %g) {
401  %ff = alloca float
402  %gg = alloca double
403  call void (i64, i32, ...) @llvm.experimental.stackmap(i64 888, i32 0, float 1.25,
404    double 1.5, float %f, double %g, float* %ff, double* %gg)
405  ret void
406}
407
408declare void @llvm.experimental.stackmap(i64, i32, ...)
409declare void @llvm.experimental.patchpoint.void(i64, i32, i8*, i32, ...)
410declare i64 @llvm.experimental.patchpoint.i64(i64, i32, i8*, i32, ...)
411