xref: /llvm-project/llvm/test/CodeGen/SystemZ/frame-15.ll (revision a1710eb3cd5823c5d14899112ca3086acbdbe9cb)
1; Test the handling of base + index + 12-bit displacement addresses for
2; large frames, in cases where no 20-bit form exists.  The tests here
3; assume z10 register pressure, without the high words being available.
4;
5; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z10 | \
6; RUN:   FileCheck -check-prefix=CHECK-NOFP %s
7; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z10 -frame-pointer=all | \
8; RUN:   FileCheck -check-prefix=CHECK-FP %s
9
10declare void @foo(ptr %ptr1, ptr %ptr2)
11
12; This file tests what happens when a displacement is converted from
13; being relative to the start of a frame object to being relative to
14; the frame itself.  In some cases the test is only possible if two
15; objects are allocated.
16;
17; Rather than rely on a particular order for those objects, the tests
18; instead allocate two objects of the same size and apply the test to
19; both of them.  For consistency, all tests follow this model, even if
20; one object would actually be enough.
21
22; First check the highest in-range offset after conversion, which is 4092
23; for word-addressing instructions like LDEB.
24;
25; The last in-range doubleword offset is 4088.  Since the frame has two
26; emergency spill slots at 160(%r15), the amount that we need to allocate
27; in order to put another object at offset 4088 is (4088 - 176) / 4 = 978
28; words.
29define void @f1(ptr %dst) {
30; CHECK-NOFP-LABEL: f1:
31; CHECK-NOFP: ldeb {{%f[0-7]}}, 4092(%r15)
32; CHECK-NOFP: br %r14
33;
34; CHECK-FP-LABEL: f1:
35; CHECK-FP: ldeb {{%f[0-7]}}, 4092(%r11)
36; CHECK-FP: br %r14
37  %region1 = alloca [978 x float], align 8
38  %region2 = alloca [978 x float], align 8
39  call void @foo(ptr %region1, ptr %region2)
40  %ptr1 = getelementptr inbounds [978 x float], ptr %region1, i64 0, i64 1
41  %ptr2 = getelementptr inbounds [978 x float], ptr %region2, i64 0, i64 1
42  %float1 = load float, ptr %ptr1
43  %float2 = load float, ptr %ptr2
44  %double1 = fpext float %float1 to double
45  %double2 = fpext float %float2 to double
46  store volatile double %double1, ptr %dst
47  store volatile double %double2, ptr %dst
48  ret void
49}
50
51; Test the first out-of-range offset.
52define void @f2(ptr %dst) {
53; CHECK-NOFP-LABEL: f2:
54; CHECK-NOFP: lghi %r1, 4096
55; CHECK-NOFP: ldeb {{%f[0-7]}}, 0(%r1,%r15)
56; CHECK-NOFP: br %r14
57;
58; CHECK-FP-LABEL: f2:
59; CHECK-FP: lghi %r1, 4096
60; CHECK-FP: ldeb {{%f[0-7]}}, 0(%r1,%r11)
61; CHECK-FP: br %r14
62  %region1 = alloca [978 x float], align 8
63  %region2 = alloca [978 x float], align 8
64  call void @foo(ptr %region1, ptr %region2)
65  %ptr1 = getelementptr inbounds [978 x float], ptr %region1, i64 0, i64 2
66  %ptr2 = getelementptr inbounds [978 x float], ptr %region2, i64 0, i64 2
67  %float1 = load float, ptr %ptr1
68  %float2 = load float, ptr %ptr2
69  %double1 = fpext float %float1 to double
70  %double2 = fpext float %float2 to double
71  store volatile double %double1, ptr %dst
72  store volatile double %double2, ptr %dst
73  ret void
74}
75
76; Test the next offset after that.
77define void @f3(ptr %dst) {
78; CHECK-NOFP-LABEL: f3:
79; CHECK-NOFP: lghi %r1, 4096
80; CHECK-NOFP: ldeb {{%f[0-7]}}, 4(%r1,%r15)
81; CHECK-NOFP: br %r14
82;
83; CHECK-FP-LABEL: f3:
84; CHECK-FP: lghi %r1, 4096
85; CHECK-FP: ldeb {{%f[0-7]}}, 4(%r1,%r11)
86; CHECK-FP: br %r14
87  %region1 = alloca [978 x float], align 8
88  %region2 = alloca [978 x float], align 8
89  call void @foo(ptr %region1, ptr %region2)
90  %ptr1 = getelementptr inbounds [978 x float], ptr %region1, i64 0, i64 3
91  %ptr2 = getelementptr inbounds [978 x float], ptr %region2, i64 0, i64 3
92  %float1 = load float, ptr %ptr1
93  %float2 = load float, ptr %ptr2
94  %double1 = fpext float %float1 to double
95  %double2 = fpext float %float2 to double
96  store volatile double %double1, ptr %dst
97  store volatile double %double2, ptr %dst
98  ret void
99}
100
101; Add 4096 bytes (1024 words) to the size of each object and repeat.
102define void @f4(ptr %dst) {
103; CHECK-NOFP-LABEL: f4:
104; CHECK-NOFP: lghi %r1, 4096
105; CHECK-NOFP: ldeb {{%f[0-7]}}, 4092(%r1,%r15)
106; CHECK-NOFP: br %r14
107;
108; CHECK-FP-LABEL: f4:
109; CHECK-FP: lghi %r1, 4096
110; CHECK-FP: ldeb {{%f[0-7]}}, 4092(%r1,%r11)
111; CHECK-FP: br %r14
112  %region1 = alloca [2002 x float], align 8
113  %region2 = alloca [2002 x float], align 8
114  call void @foo(ptr %region1, ptr %region2)
115  %ptr1 = getelementptr inbounds [2002 x float], ptr %region1, i64 0, i64 1
116  %ptr2 = getelementptr inbounds [2002 x float], ptr %region2, i64 0, i64 1
117  %float1 = load float, ptr %ptr1
118  %float2 = load float, ptr %ptr2
119  %double1 = fpext float %float1 to double
120  %double2 = fpext float %float2 to double
121  store volatile double %double1, ptr %dst
122  store volatile double %double2, ptr %dst
123  ret void
124}
125
126; ...as above.
127define void @f5(ptr %dst) {
128; CHECK-NOFP-LABEL: f5:
129; CHECK-NOFP: lghi %r1, 8192
130; CHECK-NOFP: ldeb {{%f[0-7]}}, 0(%r1,%r15)
131; CHECK-NOFP: br %r14
132;
133; CHECK-FP-LABEL: f5:
134; CHECK-FP: lghi %r1, 8192
135; CHECK-FP: ldeb {{%f[0-7]}}, 0(%r1,%r11)
136; CHECK-FP: br %r14
137  %region1 = alloca [2002 x float], align 8
138  %region2 = alloca [2002 x float], align 8
139  call void @foo(ptr %region1, ptr %region2)
140  %ptr1 = getelementptr inbounds [2002 x float], ptr %region1, i64 0, i64 2
141  %ptr2 = getelementptr inbounds [2002 x float], ptr %region2, i64 0, i64 2
142  %float1 = load float, ptr %ptr1
143  %float2 = load float, ptr %ptr2
144  %double1 = fpext float %float1 to double
145  %double2 = fpext float %float2 to double
146  store volatile double %double1, ptr %dst
147  store volatile double %double2, ptr %dst
148  ret void
149}
150
151; ...as above.
152define void @f6(ptr %dst) {
153; CHECK-NOFP-LABEL: f6:
154; CHECK-NOFP: lghi %r1, 8192
155; CHECK-NOFP: ldeb {{%f[0-7]}}, 4(%r1,%r15)
156; CHECK-NOFP: br %r14
157;
158; CHECK-FP-LABEL: f6:
159; CHECK-FP: lghi %r1, 8192
160; CHECK-FP: ldeb {{%f[0-7]}}, 4(%r1,%r11)
161; CHECK-FP: br %r14
162  %region1 = alloca [2002 x float], align 8
163  %region2 = alloca [2002 x float], align 8
164  call void @foo(ptr %region1, ptr %region2)
165  %ptr1 = getelementptr inbounds [2002 x float], ptr %region1, i64 0, i64 3
166  %ptr2 = getelementptr inbounds [2002 x float], ptr %region2, i64 0, i64 3
167  %float1 = load float, ptr %ptr1
168  %float2 = load float, ptr %ptr2
169  %double1 = fpext float %float1 to double
170  %double2 = fpext float %float2 to double
171  store volatile double %double1, ptr %dst
172  store volatile double %double2, ptr %dst
173  ret void
174}
175
176; Now try an offset of 4092 from the start of the object, with the object
177; being at offset 8192.  This time we need objects of (8192 - 168) / 4 = 2004
178; words.
179define void @f7(ptr %dst) {
180; CHECK-NOFP-LABEL: f7:
181; CHECK-NOFP: lghi %r1, 8192
182; CHECK-NOFP: ldeb {{%f[0-7]}}, 4092(%r1,%r15)
183; CHECK-NOFP: br %r14
184;
185; CHECK-FP-LABEL: f7:
186; CHECK-FP: lghi %r1, 8192
187; CHECK-FP: ldeb {{%f[0-7]}}, 4092(%r1,%r11)
188; CHECK-FP: br %r14
189  %region1 = alloca [2004 x float], align 8
190  %region2 = alloca [2004 x float], align 8
191  call void @foo(ptr %region1, ptr %region2)
192  %ptr1 = getelementptr inbounds [2004 x float], ptr %region1, i64 0, i64 1023
193  %ptr2 = getelementptr inbounds [2004 x float], ptr %region2, i64 0, i64 1023
194  %float1 = load float, ptr %ptr1
195  %float2 = load float, ptr %ptr2
196  %double1 = fpext float %float1 to double
197  %double2 = fpext float %float2 to double
198  store volatile double %double1, ptr %dst
199  store volatile double %double2, ptr %dst
200  ret void
201}
202
203; Keep the object-relative offset the same but bump the size of the
204; objects by one doubleword.
205define void @f8(ptr %dst) {
206; CHECK-NOFP-LABEL: f8:
207; CHECK-NOFP: lghi %r1, 12288
208; CHECK-NOFP: ldeb {{%f[0-7]}}, 4(%r1,%r15)
209; CHECK-NOFP: br %r14
210;
211; CHECK-FP-LABEL: f8:
212; CHECK-FP: lghi %r1, 12288
213; CHECK-FP: ldeb {{%f[0-7]}}, 4(%r1,%r11)
214; CHECK-FP: br %r14
215  %region1 = alloca [2006 x float], align 8
216  %region2 = alloca [2006 x float], align 8
217  call void @foo(ptr %region1, ptr %region2)
218  %ptr1 = getelementptr inbounds [2006 x float], ptr %region1, i64 0, i64 1023
219  %ptr2 = getelementptr inbounds [2006 x float], ptr %region2, i64 0, i64 1023
220  %float1 = load float, ptr %ptr1
221  %float2 = load float, ptr %ptr2
222  %double1 = fpext float %float1 to double
223  %double2 = fpext float %float2 to double
224  store volatile double %double1, ptr %dst
225  store volatile double %double2, ptr %dst
226  ret void
227}
228
229; Check a case where the original displacement is out of range.  The backend
230; should force an LAY from the outset.  We don't yet do any kind of anchor
231; optimization, so there should be no offset on the LDEB itself.
232define void @f9(ptr %dst) {
233; CHECK-NOFP-LABEL: f9:
234; CHECK-NOFP: lay %r1, 12296(%r15)
235; CHECK-NOFP: ldeb {{%f[0-7]}}, 0(%r1)
236; CHECK-NOFP: br %r14
237;
238; CHECK-FP-LABEL: f9:
239; CHECK-FP: lay %r1, 12296(%r11)
240; CHECK-FP: ldeb {{%f[0-7]}}, 0(%r1)
241; CHECK-FP: br %r14
242  %region1 = alloca [2006 x float], align 8
243  %region2 = alloca [2006 x float], align 8
244  call void @foo(ptr %region1, ptr %region2)
245  %ptr1 = getelementptr inbounds [2006 x float], ptr %region1, i64 0, i64 1024
246  %ptr2 = getelementptr inbounds [2006 x float], ptr %region2, i64 0, i64 1024
247  %float1 = load float, ptr %ptr1
248  %float2 = load float, ptr %ptr2
249  %double1 = fpext float %float1 to double
250  %double2 = fpext float %float2 to double
251  store volatile double %double1, ptr %dst
252  store volatile double %double2, ptr %dst
253  ret void
254}
255
256; Repeat f2 in a case that needs the emergency spill slots, because all
257; call-clobbered and allocated call-saved registers are live.  Note that
258; %vptr and %dst are copied to call-saved registers, freeing up %r2 and
259; %r3 during the main test.
260define void @f10(ptr %vptr, ptr %dst) {
261; CHECK-NOFP-LABEL: f10:
262; CHECK-NOFP: stg [[REGISTER:%r[1-9][0-4]?]], [[OFFSET:160|168]](%r15)
263; CHECK-NOFP: lghi [[REGISTER]], 4096
264; CHECK-NOFP: ldeb {{%f[0-7]}}, 0([[REGISTER]],%r15)
265; CHECK-NOFP: lg [[REGISTER]], [[OFFSET]](%r15)
266; CHECK-NOFP: br %r14
267;
268; CHECK-FP-LABEL: f10:
269; CHECK-FP: stg [[REGISTER:%r[1-9][0-4]?]], [[OFFSET:160|168]](%r11)
270; CHECK-FP: lghi [[REGISTER]], 4096
271; CHECK-FP: ldeb {{%f[0-7]}}, 0([[REGISTER]],%r11)
272; CHECK-FP: lg [[REGISTER]], [[OFFSET]](%r11)
273; CHECK-FP: br %r14
274  %region1 = alloca [978 x float], align 8
275  %region2 = alloca [978 x float], align 8
276  call void @foo(ptr %region1, ptr %region2)
277  %ptr1 = getelementptr inbounds [978 x float], ptr %region1, i64 0, i64 2
278  %ptr2 = getelementptr inbounds [978 x float], ptr %region2, i64 0, i64 2
279  %i0 = load volatile i32, ptr %vptr
280  %i1 = load volatile i32, ptr %vptr
281  %i2 = load volatile i32, ptr %vptr
282  %i3 = load volatile i32, ptr %vptr
283  %i4 = load volatile i32, ptr %vptr
284  %i5 = load volatile i32, ptr %vptr
285  %i14 = load volatile i32, ptr %vptr
286  %float1 = load float, ptr %ptr1
287  %float2 = load float, ptr %ptr2
288  %double1 = fpext float %float1 to double
289  %double2 = fpext float %float2 to double
290  store volatile double %double1, ptr %dst
291  store volatile double %double2, ptr %dst
292  store volatile i32 %i0, ptr %vptr
293  store volatile i32 %i1, ptr %vptr
294  store volatile i32 %i2, ptr %vptr
295  store volatile i32 %i3, ptr %vptr
296  store volatile i32 %i4, ptr %vptr
297  store volatile i32 %i5, ptr %vptr
298  store volatile i32 %i14, ptr %vptr
299  ret void
300}
301
302; Repeat f2 in a case where the index register is already occupied.
303define void @f11(ptr %dst, i64 %index) {
304; CHECK-NOFP-LABEL: f11:
305; CHECK-NOFP: lgr [[REGISTER:%r[1-9][0-5]?]], %r3
306; CHECK-NOFP: lay %r1, 4096(%r15)
307; CHECK-NOFP: ldeb {{%f[0-7]}}, 0([[REGISTER]],%r1)
308; CHECK-NOFP: br %r14
309;
310; CHECK-FP-LABEL: f11:
311; CHECK-FP: lgr [[REGISTER:%r[1-9][0-5]?]], %r3
312; CHECK-FP: lay %r1, 4096(%r11)
313; CHECK-FP: ldeb {{%f[0-7]}}, 0([[REGISTER]],%r1)
314; CHECK-FP: br %r14
315  %region1 = alloca [978 x float], align 8
316  %region2 = alloca [978 x float], align 8
317  call void @foo(ptr %region1, ptr %region2)
318  %elem1 = getelementptr inbounds [978 x float], ptr %region1, i64 0, i64 2
319  %elem2 = getelementptr inbounds [978 x float], ptr %region2, i64 0, i64 2
320  %base1 = ptrtoint ptr %elem1 to i64
321  %base2 = ptrtoint ptr %elem2 to i64
322  %addr1 = add i64 %base1, %index
323  %addr2 = add i64 %base2, %index
324  %ptr1 = inttoptr i64 %addr1 to ptr
325  %ptr2 = inttoptr i64 %addr2 to ptr
326  %float1 = load float, ptr %ptr1
327  %float2 = load float, ptr %ptr2
328  %double1 = fpext float %float1 to double
329  %double2 = fpext float %float2 to double
330  store volatile double %double1, ptr %dst
331  store volatile double %double2, ptr %dst
332  ret void
333}
334