1 ; RUN: llc -mtriple=aarch64-linux-gnu -aarch64-atomic-cfg-tidy=0 -verify-machineinstrs -o - %s | FileCheck %s
3 ; This file contains tests for the AArch64 load/store optimizer.
5 %padding = type { i8*, i8*, i8*, i8* }
6 %s.word = type { i32, i32 }
7 %s.doubleword = type { i64, i32 }
8 %s.quadword = type { fp128, i32 }
9 %s.float = type { float, i32 }
10 %s.double = type { double, i32 }
11 %struct.word = type { %padding, %s.word }
12 %struct.doubleword = type { %padding, %s.doubleword }
13 %struct.quadword = type { %padding, %s.quadword }
14 %struct.float = type { %padding, %s.float }
15 %struct.double = type { %padding, %s.double }
17 ; Check the following transform:
19 ; (ldr|str) X, [x0, #32]
23 ; (ldr|str) X, [x0, #32]!
25 ; with X being either w1, x1, s0, d0 or q0.
27 declare void @bar_word(%s.word*, i32)
29 define void @load-pre-indexed-word(%struct.word* %ptr) nounwind {
30 ; CHECK-LABEL: load-pre-indexed-word
31 ; CHECK: ldr w{{[0-9]+}}, [x{{[0-9]+}}, #32]!
33 %a = getelementptr inbounds %struct.word* %ptr, i64 0, i32 1, i32 0
34 %add = load i32* %a, align 4
37 %c = getelementptr inbounds %struct.word* %ptr, i64 0, i32 1
38 tail call void @bar_word(%s.word* %c, i32 %add)
42 define void @store-pre-indexed-word(%struct.word* %ptr, i32 %val) nounwind {
43 ; CHECK-LABEL: store-pre-indexed-word
44 ; CHECK: str w{{[0-9]+}}, [x{{[0-9]+}}, #32]!
46 %a = getelementptr inbounds %struct.word* %ptr, i64 0, i32 1, i32 0
47 store i32 %val, i32* %a, align 4
50 %c = getelementptr inbounds %struct.word* %ptr, i64 0, i32 1
51 tail call void @bar_word(%s.word* %c, i32 %val)
55 declare void @bar_doubleword(%s.doubleword*, i64)
57 define void @load-pre-indexed-doubleword(%struct.doubleword* %ptr) nounwind {
58 ; CHECK-LABEL: load-pre-indexed-doubleword
59 ; CHECK: ldr x{{[0-9]+}}, [x{{[0-9]+}}, #32]!
61 %a = getelementptr inbounds %struct.doubleword* %ptr, i64 0, i32 1, i32 0
62 %add = load i64* %a, align 4
65 %c = getelementptr inbounds %struct.doubleword* %ptr, i64 0, i32 1
66 tail call void @bar_doubleword(%s.doubleword* %c, i64 %add)
70 define void @store-pre-indexed-doubleword(%struct.doubleword* %ptr, i64 %val) nounwind {
71 ; CHECK-LABEL: store-pre-indexed-doubleword
72 ; CHECK: str x{{[0-9]+}}, [x{{[0-9]+}}, #32]!
74 %a = getelementptr inbounds %struct.doubleword* %ptr, i64 0, i32 1, i32 0
75 store i64 %val, i64* %a, align 4
78 %c = getelementptr inbounds %struct.doubleword* %ptr, i64 0, i32 1
79 tail call void @bar_doubleword(%s.doubleword* %c, i64 %val)
83 declare void @bar_quadword(%s.quadword*, fp128)
85 define void @load-pre-indexed-quadword(%struct.quadword* %ptr) nounwind {
86 ; CHECK-LABEL: load-pre-indexed-quadword
87 ; CHECK: ldr q{{[0-9]+}}, [x{{[0-9]+}}, #32]!
89 %a = getelementptr inbounds %struct.quadword* %ptr, i64 0, i32 1, i32 0
90 %add = load fp128* %a, align 4
93 %c = getelementptr inbounds %struct.quadword* %ptr, i64 0, i32 1
94 tail call void @bar_quadword(%s.quadword* %c, fp128 %add)
98 define void @store-pre-indexed-quadword(%struct.quadword* %ptr, fp128 %val) nounwind {
99 ; CHECK-LABEL: store-pre-indexed-quadword
100 ; CHECK: str q{{[0-9]+}}, [x{{[0-9]+}}, #32]!
102 %a = getelementptr inbounds %struct.quadword* %ptr, i64 0, i32 1, i32 0
103 store fp128 %val, fp128* %a, align 4
106 %c = getelementptr inbounds %struct.quadword* %ptr, i64 0, i32 1
107 tail call void @bar_quadword(%s.quadword* %c, fp128 %val)
111 declare void @bar_float(%s.float*, float)
113 define void @load-pre-indexed-float(%struct.float* %ptr) nounwind {
114 ; CHECK-LABEL: load-pre-indexed-float
115 ; CHECK: ldr s{{[0-9]+}}, [x{{[0-9]+}}, #32]!
117 %a = getelementptr inbounds %struct.float* %ptr, i64 0, i32 1, i32 0
118 %add = load float* %a, align 4
121 %c = getelementptr inbounds %struct.float* %ptr, i64 0, i32 1
122 tail call void @bar_float(%s.float* %c, float %add)
126 define void @store-pre-indexed-float(%struct.float* %ptr, float %val) nounwind {
127 ; CHECK-LABEL: store-pre-indexed-float
128 ; CHECK: str s{{[0-9]+}}, [x{{[0-9]+}}, #32]!
130 %a = getelementptr inbounds %struct.float* %ptr, i64 0, i32 1, i32 0
131 store float %val, float* %a, align 4
134 %c = getelementptr inbounds %struct.float* %ptr, i64 0, i32 1
135 tail call void @bar_float(%s.float* %c, float %val)
139 declare void @bar_double(%s.double*, double)
141 define void @load-pre-indexed-double(%struct.double* %ptr) nounwind {
142 ; CHECK-LABEL: load-pre-indexed-double
143 ; CHECK: ldr d{{[0-9]+}}, [x{{[0-9]+}}, #32]!
145 %a = getelementptr inbounds %struct.double* %ptr, i64 0, i32 1, i32 0
146 %add = load double* %a, align 4
149 %c = getelementptr inbounds %struct.double* %ptr, i64 0, i32 1
150 tail call void @bar_double(%s.double* %c, double %add)
154 define void @store-pre-indexed-double(%struct.double* %ptr, double %val) nounwind {
155 ; CHECK-LABEL: store-pre-indexed-double
156 ; CHECK: str d{{[0-9]+}}, [x{{[0-9]+}}, #32]!
158 %a = getelementptr inbounds %struct.double* %ptr, i64 0, i32 1, i32 0
159 store double %val, double* %a, align 4
162 %c = getelementptr inbounds %struct.double* %ptr, i64 0, i32 1
163 tail call void @bar_double(%s.double* %c, double %val)
167 ; Check the following transform:
175 ; with X being either w0, x0, s0, d0 or q0.
177 %pre.struct.i32 = type { i32, i32, i32}
178 %pre.struct.i64 = type { i32, i64, i64}
179 %pre.struct.i128 = type { i32, <2 x i64>, <2 x i64>}
180 %pre.struct.float = type { i32, float, float}
181 %pre.struct.double = type { i32, double, double}
183 define i32 @load-pre-indexed-word2(%pre.struct.i32** %this, i1 %cond,
184 %pre.struct.i32* %load2) nounwind {
185 ; CHECK-LABEL: load-pre-indexed-word2
186 ; CHECK: ldr w{{[0-9]+}}, [x{{[0-9]+}}, #4]!
187 br i1 %cond, label %if.then, label %if.end
189 %load1 = load %pre.struct.i32** %this
190 %gep1 = getelementptr inbounds %pre.struct.i32* %load1, i64 0, i32 1
193 %gep2 = getelementptr inbounds %pre.struct.i32* %load2, i64 0, i32 2
196 %retptr = phi i32* [ %gep1, %if.then ], [ %gep2, %if.end ]
197 %ret = load i32* %retptr
201 define i64 @load-pre-indexed-doubleword2(%pre.struct.i64** %this, i1 %cond,
202 %pre.struct.i64* %load2) nounwind {
203 ; CHECK-LABEL: load-pre-indexed-doubleword2
204 ; CHECK: ldr x{{[0-9]+}}, [x{{[0-9]+}}, #8]!
205 br i1 %cond, label %if.then, label %if.end
207 %load1 = load %pre.struct.i64** %this
208 %gep1 = getelementptr inbounds %pre.struct.i64* %load1, i64 0, i32 1
211 %gep2 = getelementptr inbounds %pre.struct.i64* %load2, i64 0, i32 2
214 %retptr = phi i64* [ %gep1, %if.then ], [ %gep2, %if.end ]
215 %ret = load i64* %retptr
219 define <2 x i64> @load-pre-indexed-quadword2(%pre.struct.i128** %this, i1 %cond,
220 %pre.struct.i128* %load2) nounwind {
221 ; CHECK-LABEL: load-pre-indexed-quadword2
222 ; CHECK: ldr q{{[0-9]+}}, [x{{[0-9]+}}, #16]!
223 br i1 %cond, label %if.then, label %if.end
225 %load1 = load %pre.struct.i128** %this
226 %gep1 = getelementptr inbounds %pre.struct.i128* %load1, i64 0, i32 1
229 %gep2 = getelementptr inbounds %pre.struct.i128* %load2, i64 0, i32 2
232 %retptr = phi <2 x i64>* [ %gep1, %if.then ], [ %gep2, %if.end ]
233 %ret = load <2 x i64>* %retptr
237 define float @load-pre-indexed-float2(%pre.struct.float** %this, i1 %cond,
238 %pre.struct.float* %load2) nounwind {
239 ; CHECK-LABEL: load-pre-indexed-float2
240 ; CHECK: ldr s{{[0-9]+}}, [x{{[0-9]+}}, #4]!
241 br i1 %cond, label %if.then, label %if.end
243 %load1 = load %pre.struct.float** %this
244 %gep1 = getelementptr inbounds %pre.struct.float* %load1, i64 0, i32 1
247 %gep2 = getelementptr inbounds %pre.struct.float* %load2, i64 0, i32 2
250 %retptr = phi float* [ %gep1, %if.then ], [ %gep2, %if.end ]
251 %ret = load float* %retptr
255 define double @load-pre-indexed-double2(%pre.struct.double** %this, i1 %cond,
256 %pre.struct.double* %load2) nounwind {
257 ; CHECK-LABEL: load-pre-indexed-double2
258 ; CHECK: ldr d{{[0-9]+}}, [x{{[0-9]+}}, #8]!
259 br i1 %cond, label %if.then, label %if.end
261 %load1 = load %pre.struct.double** %this
262 %gep1 = getelementptr inbounds %pre.struct.double* %load1, i64 0, i32 1
265 %gep2 = getelementptr inbounds %pre.struct.double* %load2, i64 0, i32 2
268 %retptr = phi double* [ %gep1, %if.then ], [ %gep2, %if.end ]
269 %ret = load double* %retptr
273 ; Check the following transform:
281 ; with X being either w0, x0, s0, d0 or q0.
283 define void @load-post-indexed-word(i32* %array, i64 %count) nounwind {
284 ; CHECK-LABEL: load-post-indexed-word
285 ; CHECK: ldr w{{[0-9]+}}, [x{{[0-9]+}}], #16
287 %gep1 = getelementptr i32* %array, i64 2
291 %iv2 = phi i32* [ %gep3, %body ], [ %gep1, %entry ]
292 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
293 %gep2 = getelementptr i32* %iv2, i64 -1
294 %load = load i32* %gep2
295 call void @use-word(i32 %load)
296 %load2 = load i32* %iv2
297 call void @use-word(i32 %load2)
298 %iv.next = add i64 %iv, -4
299 %gep3 = getelementptr i32* %iv2, i64 4
300 %cond = icmp eq i64 %iv.next, 0
301 br i1 %cond, label %exit, label %body
307 define void @load-post-indexed-doubleword(i64* %array, i64 %count) nounwind {
308 ; CHECK-LABEL: load-post-indexed-doubleword
309 ; CHECK: ldr x{{[0-9]+}}, [x{{[0-9]+}}], #32
311 %gep1 = getelementptr i64* %array, i64 2
315 %iv2 = phi i64* [ %gep3, %body ], [ %gep1, %entry ]
316 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
317 %gep2 = getelementptr i64* %iv2, i64 -1
318 %load = load i64* %gep2
319 call void @use-doubleword(i64 %load)
320 %load2 = load i64* %iv2
321 call void @use-doubleword(i64 %load2)
322 %iv.next = add i64 %iv, -4
323 %gep3 = getelementptr i64* %iv2, i64 4
324 %cond = icmp eq i64 %iv.next, 0
325 br i1 %cond, label %exit, label %body
331 define void @load-post-indexed-quadword(<2 x i64>* %array, i64 %count) nounwind {
332 ; CHECK-LABEL: load-post-indexed-quadword
333 ; CHECK: ldr q{{[0-9]+}}, [x{{[0-9]+}}], #64
335 %gep1 = getelementptr <2 x i64>* %array, i64 2
339 %iv2 = phi <2 x i64>* [ %gep3, %body ], [ %gep1, %entry ]
340 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
341 %gep2 = getelementptr <2 x i64>* %iv2, i64 -1
342 %load = load <2 x i64>* %gep2
343 call void @use-quadword(<2 x i64> %load)
344 %load2 = load <2 x i64>* %iv2
345 call void @use-quadword(<2 x i64> %load2)
346 %iv.next = add i64 %iv, -4
347 %gep3 = getelementptr <2 x i64>* %iv2, i64 4
348 %cond = icmp eq i64 %iv.next, 0
349 br i1 %cond, label %exit, label %body
355 define void @load-post-indexed-float(float* %array, i64 %count) nounwind {
356 ; CHECK-LABEL: load-post-indexed-float
357 ; CHECK: ldr s{{[0-9]+}}, [x{{[0-9]+}}], #16
359 %gep1 = getelementptr float* %array, i64 2
363 %iv2 = phi float* [ %gep3, %body ], [ %gep1, %entry ]
364 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
365 %gep2 = getelementptr float* %iv2, i64 -1
366 %load = load float* %gep2
367 call void @use-float(float %load)
368 %load2 = load float* %iv2
369 call void @use-float(float %load2)
370 %iv.next = add i64 %iv, -4
371 %gep3 = getelementptr float* %iv2, i64 4
372 %cond = icmp eq i64 %iv.next, 0
373 br i1 %cond, label %exit, label %body
379 define void @load-post-indexed-double(double* %array, i64 %count) nounwind {
380 ; CHECK-LABEL: load-post-indexed-double
381 ; CHECK: ldr d{{[0-9]+}}, [x{{[0-9]+}}], #32
383 %gep1 = getelementptr double* %array, i64 2
387 %iv2 = phi double* [ %gep3, %body ], [ %gep1, %entry ]
388 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
389 %gep2 = getelementptr double* %iv2, i64 -1
390 %load = load double* %gep2
391 call void @use-double(double %load)
392 %load2 = load double* %iv2
393 call void @use-double(double %load2)
394 %iv.next = add i64 %iv, -4
395 %gep3 = getelementptr double* %iv2, i64 4
396 %cond = icmp eq i64 %iv.next, 0
397 br i1 %cond, label %exit, label %body
403 ; Check the following transform:
411 ; with X being either w0, x0, s0, d0 or q0.
413 define void @store-post-indexed-word(i32* %array, i64 %count, i32 %val) nounwind {
414 ; CHECK-LABEL: store-post-indexed-word
415 ; CHECK: str w{{[0-9]+}}, [x{{[0-9]+}}], #16
417 %gep1 = getelementptr i32* %array, i64 2
421 %iv2 = phi i32* [ %gep3, %body ], [ %gep1, %entry ]
422 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
423 %gep2 = getelementptr i32* %iv2, i64 -1
424 %load = load i32* %gep2
425 call void @use-word(i32 %load)
426 store i32 %val, i32* %iv2
427 %iv.next = add i64 %iv, -4
428 %gep3 = getelementptr i32* %iv2, i64 4
429 %cond = icmp eq i64 %iv.next, 0
430 br i1 %cond, label %exit, label %body
436 define void @store-post-indexed-doubleword(i64* %array, i64 %count, i64 %val) nounwind {
437 ; CHECK-LABEL: store-post-indexed-doubleword
438 ; CHECK: str x{{[0-9]+}}, [x{{[0-9]+}}], #32
440 %gep1 = getelementptr i64* %array, i64 2
444 %iv2 = phi i64* [ %gep3, %body ], [ %gep1, %entry ]
445 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
446 %gep2 = getelementptr i64* %iv2, i64 -1
447 %load = load i64* %gep2
448 call void @use-doubleword(i64 %load)
449 store i64 %val, i64* %iv2
450 %iv.next = add i64 %iv, -4
451 %gep3 = getelementptr i64* %iv2, i64 4
452 %cond = icmp eq i64 %iv.next, 0
453 br i1 %cond, label %exit, label %body
459 define void @store-post-indexed-quadword(<2 x i64>* %array, i64 %count, <2 x i64> %val) nounwind {
460 ; CHECK-LABEL: store-post-indexed-quadword
461 ; CHECK: str q{{[0-9]+}}, [x{{[0-9]+}}], #64
463 %gep1 = getelementptr <2 x i64>* %array, i64 2
467 %iv2 = phi <2 x i64>* [ %gep3, %body ], [ %gep1, %entry ]
468 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
469 %gep2 = getelementptr <2 x i64>* %iv2, i64 -1
470 %load = load <2 x i64>* %gep2
471 call void @use-quadword(<2 x i64> %load)
472 store <2 x i64> %val, <2 x i64>* %iv2
473 %iv.next = add i64 %iv, -4
474 %gep3 = getelementptr <2 x i64>* %iv2, i64 4
475 %cond = icmp eq i64 %iv.next, 0
476 br i1 %cond, label %exit, label %body
482 define void @store-post-indexed-float(float* %array, i64 %count, float %val) nounwind {
483 ; CHECK-LABEL: store-post-indexed-float
484 ; CHECK: str s{{[0-9]+}}, [x{{[0-9]+}}], #16
486 %gep1 = getelementptr float* %array, i64 2
490 %iv2 = phi float* [ %gep3, %body ], [ %gep1, %entry ]
491 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
492 %gep2 = getelementptr float* %iv2, i64 -1
493 %load = load float* %gep2
494 call void @use-float(float %load)
495 store float %val, float* %iv2
496 %iv.next = add i64 %iv, -4
497 %gep3 = getelementptr float* %iv2, i64 4
498 %cond = icmp eq i64 %iv.next, 0
499 br i1 %cond, label %exit, label %body
505 define void @store-post-indexed-double(double* %array, i64 %count, double %val) nounwind {
506 ; CHECK-LABEL: store-post-indexed-double
507 ; CHECK: str d{{[0-9]+}}, [x{{[0-9]+}}], #32
509 %gep1 = getelementptr double* %array, i64 2
513 %iv2 = phi double* [ %gep3, %body ], [ %gep1, %entry ]
514 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
515 %gep2 = getelementptr double* %iv2, i64 -1
516 %load = load double* %gep2
517 call void @use-double(double %load)
518 store double %val, double* %iv2
519 %iv.next = add i64 %iv, -4
520 %gep3 = getelementptr double* %iv2, i64 4
521 %cond = icmp eq i64 %iv.next, 0
522 br i1 %cond, label %exit, label %body
528 declare void @use-word(i32)
529 declare void @use-doubleword(i64)
530 declare void @use-quadword(<2 x i64>)
531 declare void @use-float(float)
532 declare void @use-double(double)