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.
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
10 declare void @foo(float *%ptr1, float *%ptr2)
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.
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.
22 ; First check the highest in-range offset after conversion, which is 4092
23 ; for word-addressing instructions like LDEB.
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
29 define void @f1(double *%dst) {
30 ; CHECK-NOFP-LABEL: f1:
31 ; CHECK-NOFP: ldeb {{%f[0-7]}}, 4092(%r15)
35 ; CHECK-FP: ldeb {{%f[0-7]}}, 4092(%r11)
37 %region1 = alloca [978 x float], align 8
38 %region2 = alloca [978 x float], align 8
39 %start1 = getelementptr inbounds [978 x float], [978 x float]* %region1, i64 0, i64 0
40 %start2 = getelementptr inbounds [978 x float], [978 x float]* %region2, i64 0, i64 0
41 call void @foo(float *%start1, float *%start2)
42 %ptr1 = getelementptr inbounds [978 x float], [978 x float]* %region1, i64 0, i64 1
43 %ptr2 = getelementptr inbounds [978 x float], [978 x float]* %region2, i64 0, i64 1
44 %float1 = load float, float *%ptr1
45 %float2 = load float, float *%ptr2
46 %double1 = fpext float %float1 to double
47 %double2 = fpext float %float2 to double
48 store volatile double %double1, double *%dst
49 store volatile double %double2, double *%dst
53 ; Test the first out-of-range offset.
54 define void @f2(double *%dst) {
55 ; CHECK-NOFP-LABEL: f2:
56 ; CHECK-NOFP: lghi %r1, 4096
57 ; CHECK-NOFP: ldeb {{%f[0-7]}}, 0(%r1,%r15)
61 ; CHECK-FP: lghi %r1, 4096
62 ; CHECK-FP: ldeb {{%f[0-7]}}, 0(%r1,%r11)
64 %region1 = alloca [978 x float], align 8
65 %region2 = alloca [978 x float], align 8
66 %start1 = getelementptr inbounds [978 x float], [978 x float]* %region1, i64 0, i64 0
67 %start2 = getelementptr inbounds [978 x float], [978 x float]* %region2, i64 0, i64 0
68 call void @foo(float *%start1, float *%start2)
69 %ptr1 = getelementptr inbounds [978 x float], [978 x float]* %region1, i64 0, i64 2
70 %ptr2 = getelementptr inbounds [978 x float], [978 x float]* %region2, i64 0, i64 2
71 %float1 = load float, float *%ptr1
72 %float2 = load float, float *%ptr2
73 %double1 = fpext float %float1 to double
74 %double2 = fpext float %float2 to double
75 store volatile double %double1, double *%dst
76 store volatile double %double2, double *%dst
80 ; Test the next offset after that.
81 define void @f3(double *%dst) {
82 ; CHECK-NOFP-LABEL: f3:
83 ; CHECK-NOFP: lghi %r1, 4096
84 ; CHECK-NOFP: ldeb {{%f[0-7]}}, 4(%r1,%r15)
88 ; CHECK-FP: lghi %r1, 4096
89 ; CHECK-FP: ldeb {{%f[0-7]}}, 4(%r1,%r11)
91 %region1 = alloca [978 x float], align 8
92 %region2 = alloca [978 x float], align 8
93 %start1 = getelementptr inbounds [978 x float], [978 x float]* %region1, i64 0, i64 0
94 %start2 = getelementptr inbounds [978 x float], [978 x float]* %region2, i64 0, i64 0
95 call void @foo(float *%start1, float *%start2)
96 %ptr1 = getelementptr inbounds [978 x float], [978 x float]* %region1, i64 0, i64 3
97 %ptr2 = getelementptr inbounds [978 x float], [978 x float]* %region2, i64 0, i64 3
98 %float1 = load float, float *%ptr1
99 %float2 = load float, float *%ptr2
100 %double1 = fpext float %float1 to double
101 %double2 = fpext float %float2 to double
102 store volatile double %double1, double *%dst
103 store volatile double %double2, double *%dst
107 ; Add 4096 bytes (1024 words) to the size of each object and repeat.
108 define void @f4(double *%dst) {
109 ; CHECK-NOFP-LABEL: f4:
110 ; CHECK-NOFP: lghi %r1, 4096
111 ; CHECK-NOFP: ldeb {{%f[0-7]}}, 4092(%r1,%r15)
112 ; CHECK-NOFP: br %r14
114 ; CHECK-FP-LABEL: f4:
115 ; CHECK-FP: lghi %r1, 4096
116 ; CHECK-FP: ldeb {{%f[0-7]}}, 4092(%r1,%r11)
118 %region1 = alloca [2002 x float], align 8
119 %region2 = alloca [2002 x float], align 8
120 %start1 = getelementptr inbounds [2002 x float], [2002 x float]* %region1, i64 0, i64 0
121 %start2 = getelementptr inbounds [2002 x float], [2002 x float]* %region2, i64 0, i64 0
122 call void @foo(float *%start1, float *%start2)
123 %ptr1 = getelementptr inbounds [2002 x float], [2002 x float]* %region1, i64 0, i64 1
124 %ptr2 = getelementptr inbounds [2002 x float], [2002 x float]* %region2, i64 0, i64 1
125 %float1 = load float, float *%ptr1
126 %float2 = load float, float *%ptr2
127 %double1 = fpext float %float1 to double
128 %double2 = fpext float %float2 to double
129 store volatile double %double1, double *%dst
130 store volatile double %double2, double *%dst
135 define void @f5(double *%dst) {
136 ; CHECK-NOFP-LABEL: f5:
137 ; CHECK-NOFP: lghi %r1, 8192
138 ; CHECK-NOFP: ldeb {{%f[0-7]}}, 0(%r1,%r15)
139 ; CHECK-NOFP: br %r14
141 ; CHECK-FP-LABEL: f5:
142 ; CHECK-FP: lghi %r1, 8192
143 ; CHECK-FP: ldeb {{%f[0-7]}}, 0(%r1,%r11)
145 %region1 = alloca [2002 x float], align 8
146 %region2 = alloca [2002 x float], align 8
147 %start1 = getelementptr inbounds [2002 x float], [2002 x float]* %region1, i64 0, i64 0
148 %start2 = getelementptr inbounds [2002 x float], [2002 x float]* %region2, i64 0, i64 0
149 call void @foo(float *%start1, float *%start2)
150 %ptr1 = getelementptr inbounds [2002 x float], [2002 x float]* %region1, i64 0, i64 2
151 %ptr2 = getelementptr inbounds [2002 x float], [2002 x float]* %region2, i64 0, i64 2
152 %float1 = load float, float *%ptr1
153 %float2 = load float, float *%ptr2
154 %double1 = fpext float %float1 to double
155 %double2 = fpext float %float2 to double
156 store volatile double %double1, double *%dst
157 store volatile double %double2, double *%dst
162 define void @f6(double *%dst) {
163 ; CHECK-NOFP-LABEL: f6:
164 ; CHECK-NOFP: lghi %r1, 8192
165 ; CHECK-NOFP: ldeb {{%f[0-7]}}, 4(%r1,%r15)
166 ; CHECK-NOFP: br %r14
168 ; CHECK-FP-LABEL: f6:
169 ; CHECK-FP: lghi %r1, 8192
170 ; CHECK-FP: ldeb {{%f[0-7]}}, 4(%r1,%r11)
172 %region1 = alloca [2002 x float], align 8
173 %region2 = alloca [2002 x float], align 8
174 %start1 = getelementptr inbounds [2002 x float], [2002 x float]* %region1, i64 0, i64 0
175 %start2 = getelementptr inbounds [2002 x float], [2002 x float]* %region2, i64 0, i64 0
176 call void @foo(float *%start1, float *%start2)
177 %ptr1 = getelementptr inbounds [2002 x float], [2002 x float]* %region1, i64 0, i64 3
178 %ptr2 = getelementptr inbounds [2002 x float], [2002 x float]* %region2, i64 0, i64 3
179 %float1 = load float, float *%ptr1
180 %float2 = load float, float *%ptr2
181 %double1 = fpext float %float1 to double
182 %double2 = fpext float %float2 to double
183 store volatile double %double1, double *%dst
184 store volatile double %double2, double *%dst
188 ; Now try an offset of 4092 from the start of the object, with the object
189 ; being at offset 8192. This time we need objects of (8192 - 168) / 4 = 2004
191 define void @f7(double *%dst) {
192 ; CHECK-NOFP-LABEL: f7:
193 ; CHECK-NOFP: lghi %r1, 8192
194 ; CHECK-NOFP: ldeb {{%f[0-7]}}, 4092(%r1,%r15)
195 ; CHECK-NOFP: br %r14
197 ; CHECK-FP-LABEL: f7:
198 ; CHECK-FP: lghi %r1, 8192
199 ; CHECK-FP: ldeb {{%f[0-7]}}, 4092(%r1,%r11)
201 %region1 = alloca [2004 x float], align 8
202 %region2 = alloca [2004 x float], align 8
203 %start1 = getelementptr inbounds [2004 x float], [2004 x float]* %region1, i64 0, i64 0
204 %start2 = getelementptr inbounds [2004 x float], [2004 x float]* %region2, i64 0, i64 0
205 call void @foo(float *%start1, float *%start2)
206 %ptr1 = getelementptr inbounds [2004 x float], [2004 x float]* %region1, i64 0, i64 1023
207 %ptr2 = getelementptr inbounds [2004 x float], [2004 x float]* %region2, i64 0, i64 1023
208 %float1 = load float, float *%ptr1
209 %float2 = load float, float *%ptr2
210 %double1 = fpext float %float1 to double
211 %double2 = fpext float %float2 to double
212 store volatile double %double1, double *%dst
213 store volatile double %double2, double *%dst
217 ; Keep the object-relative offset the same but bump the size of the
218 ; objects by one doubleword.
219 define void @f8(double *%dst) {
220 ; CHECK-NOFP-LABEL: f8:
221 ; CHECK-NOFP: lghi %r1, 12288
222 ; CHECK-NOFP: ldeb {{%f[0-7]}}, 4(%r1,%r15)
223 ; CHECK-NOFP: br %r14
225 ; CHECK-FP-LABEL: f8:
226 ; CHECK-FP: lghi %r1, 12288
227 ; CHECK-FP: ldeb {{%f[0-7]}}, 4(%r1,%r11)
229 %region1 = alloca [2006 x float], align 8
230 %region2 = alloca [2006 x float], align 8
231 %start1 = getelementptr inbounds [2006 x float], [2006 x float]* %region1, i64 0, i64 0
232 %start2 = getelementptr inbounds [2006 x float], [2006 x float]* %region2, i64 0, i64 0
233 call void @foo(float *%start1, float *%start2)
234 %ptr1 = getelementptr inbounds [2006 x float], [2006 x float]* %region1, i64 0, i64 1023
235 %ptr2 = getelementptr inbounds [2006 x float], [2006 x float]* %region2, i64 0, i64 1023
236 %float1 = load float, float *%ptr1
237 %float2 = load float, float *%ptr2
238 %double1 = fpext float %float1 to double
239 %double2 = fpext float %float2 to double
240 store volatile double %double1, double *%dst
241 store volatile double %double2, double *%dst
245 ; Check a case where the original displacement is out of range. The backend
246 ; should force an LAY from the outset. We don't yet do any kind of anchor
247 ; optimization, so there should be no offset on the LDEB itself.
248 define void @f9(double *%dst) {
249 ; CHECK-NOFP-LABEL: f9:
250 ; CHECK-NOFP: lay %r1, 12296(%r15)
251 ; CHECK-NOFP: ldeb {{%f[0-7]}}, 0(%r1)
252 ; CHECK-NOFP: br %r14
254 ; CHECK-FP-LABEL: f9:
255 ; CHECK-FP: lay %r1, 12296(%r11)
256 ; CHECK-FP: ldeb {{%f[0-7]}}, 0(%r1)
258 %region1 = alloca [2006 x float], align 8
259 %region2 = alloca [2006 x float], align 8
260 %start1 = getelementptr inbounds [2006 x float], [2006 x float]* %region1, i64 0, i64 0
261 %start2 = getelementptr inbounds [2006 x float], [2006 x float]* %region2, i64 0, i64 0
262 call void @foo(float *%start1, float *%start2)
263 %ptr1 = getelementptr inbounds [2006 x float], [2006 x float]* %region1, i64 0, i64 1024
264 %ptr2 = getelementptr inbounds [2006 x float], [2006 x float]* %region2, i64 0, i64 1024
265 %float1 = load float, float *%ptr1
266 %float2 = load float, float *%ptr2
267 %double1 = fpext float %float1 to double
268 %double2 = fpext float %float2 to double
269 store volatile double %double1, double *%dst
270 store volatile double %double2, double *%dst
274 ; Repeat f2 in a case that needs the emergency spill slots, because all
275 ; call-clobbered and allocated call-saved registers are live. Note that
276 ; %vptr and %dst are copied to call-saved registers, freeing up %r2 and
277 ; %r3 during the main test.
278 define void @f10(i32 *%vptr, double *%dst) {
279 ; CHECK-NOFP-LABEL: f10:
280 ; CHECK-NOFP: stg [[REGISTER:%r[1-9][0-4]?]], [[OFFSET:160|168]](%r15)
281 ; CHECK-NOFP: lghi [[REGISTER]], 4096
282 ; CHECK-NOFP: ldeb {{%f[0-7]}}, 0([[REGISTER]],%r15)
283 ; CHECK-NOFP: lg [[REGISTER]], [[OFFSET]](%r15)
284 ; CHECK-NOFP: br %r14
286 ; CHECK-FP-LABEL: f10:
287 ; CHECK-FP: stg [[REGISTER:%r[1-9][0-4]?]], [[OFFSET:160|168]](%r11)
288 ; CHECK-FP: lghi [[REGISTER]], 4096
289 ; CHECK-FP: ldeb {{%f[0-7]}}, 0([[REGISTER]],%r11)
290 ; CHECK-FP: lg [[REGISTER]], [[OFFSET]](%r11)
292 %region1 = alloca [978 x float], align 8
293 %region2 = alloca [978 x float], align 8
294 %start1 = getelementptr inbounds [978 x float], [978 x float]* %region1, i64 0, i64 0
295 %start2 = getelementptr inbounds [978 x float], [978 x float]* %region2, i64 0, i64 0
296 call void @foo(float *%start1, float *%start2)
297 %ptr1 = getelementptr inbounds [978 x float], [978 x float]* %region1, i64 0, i64 2
298 %ptr2 = getelementptr inbounds [978 x float], [978 x float]* %region2, i64 0, i64 2
299 %i0 = load volatile i32, i32 *%vptr
300 %i1 = load volatile i32, i32 *%vptr
301 %i2 = load volatile i32, i32 *%vptr
302 %i3 = load volatile i32, i32 *%vptr
303 %i4 = load volatile i32, i32 *%vptr
304 %i5 = load volatile i32, i32 *%vptr
305 %i14 = load volatile i32, i32 *%vptr
306 %float1 = load float, float *%ptr1
307 %float2 = load float, float *%ptr2
308 %double1 = fpext float %float1 to double
309 %double2 = fpext float %float2 to double
310 store volatile double %double1, double *%dst
311 store volatile double %double2, double *%dst
312 store volatile i32 %i0, i32 *%vptr
313 store volatile i32 %i1, i32 *%vptr
314 store volatile i32 %i2, i32 *%vptr
315 store volatile i32 %i3, i32 *%vptr
316 store volatile i32 %i4, i32 *%vptr
317 store volatile i32 %i5, i32 *%vptr
318 store volatile i32 %i14, i32 *%vptr
322 ; Repeat f2 in a case where the index register is already occupied.
323 define void @f11(double *%dst, i64 %index) {
324 ; CHECK-NOFP-LABEL: f11:
325 ; CHECK-NOFP: lgr [[REGISTER:%r[1-9][0-5]?]], %r3
326 ; CHECK-NOFP: lay %r1, 4096(%r15)
327 ; CHECK-NOFP: ldeb {{%f[0-7]}}, 0([[REGISTER]],%r1)
328 ; CHECK-NOFP: br %r14
330 ; CHECK-FP-LABEL: f11:
331 ; CHECK-FP: lgr [[REGISTER:%r[1-9][0-5]?]], %r3
332 ; CHECK-FP: lay %r1, 4096(%r11)
333 ; CHECK-FP: ldeb {{%f[0-7]}}, 0([[REGISTER]],%r1)
335 %region1 = alloca [978 x float], align 8
336 %region2 = alloca [978 x float], align 8
337 %start1 = getelementptr inbounds [978 x float], [978 x float]* %region1, i64 0, i64 0
338 %start2 = getelementptr inbounds [978 x float], [978 x float]* %region2, i64 0, i64 0
339 call void @foo(float *%start1, float *%start2)
340 %elem1 = getelementptr inbounds [978 x float], [978 x float]* %region1, i64 0, i64 2
341 %elem2 = getelementptr inbounds [978 x float], [978 x float]* %region2, i64 0, i64 2
342 %base1 = ptrtoint float *%elem1 to i64
343 %base2 = ptrtoint float *%elem2 to i64
344 %addr1 = add i64 %base1, %index
345 %addr2 = add i64 %base2, %index
346 %ptr1 = inttoptr i64 %addr1 to float *
347 %ptr2 = inttoptr i64 %addr2 to float *
348 %float1 = load float, float *%ptr1
349 %float2 = load float, float *%ptr2
350 %double1 = fpext float %float1 to double
351 %double2 = fpext float %float2 to double
352 store volatile double %double1, double *%dst
353 store volatile double %double2, double *%dst