1 ; RUN: llc -mtriple=aarch64-linux-gnu -aarch64-enable-atomic-cfg-tidy=0 -disable-lsr -verify-machineinstrs -o - %s | FileCheck --check-prefix=CHECK --check-prefix=NOSTRICTALIGN %s
2 ; RUN: llc -mtriple=aarch64-linux-gnu -mattr=+strict-align -aarch64-enable-atomic-cfg-tidy=0 -disable-lsr -verify-machineinstrs -o - %s | FileCheck --check-prefix=CHECK --check-prefix=STRICTALIGN %s
4 ; This file contains tests for the AArch64 load/store optimizer.
6 %padding = type { ptr, ptr, ptr, ptr }
7 %s.byte = type { i8, i8 }
8 %s.halfword = type { i16, i16 }
9 %s.word = type { i32, i32 }
10 %s.doubleword = type { i64, i32 }
11 %s.quadword = type { fp128, i32 }
12 %s.float = type { float, i32 }
13 %s.double = type { double, i32 }
14 %struct.byte = type { %padding, %s.byte }
15 %struct.halfword = type { %padding, %s.halfword }
16 %struct.word = type { %padding, %s.word }
17 %struct.doubleword = type { %padding, %s.doubleword }
18 %struct.quadword = type { %padding, %s.quadword }
19 %struct.float = type { %padding, %s.float }
20 %struct.double = type { %padding, %s.double }
22 ; Check the following transform:
24 ; (ldr|str) X, [x0, #32]
28 ; (ldr|str) X, [x0, #32]!
30 ; with X being either w1, x1, s0, d0 or q0.
32 declare void @bar_byte(ptr, i8)
34 define void @load-pre-indexed-byte(ptr %ptr) nounwind {
35 ; CHECK-LABEL: load-pre-indexed-byte
36 ; CHECK: ldrb w{{[0-9]+}}, [x{{[0-9]+}}, #32]!
38 %a = getelementptr inbounds %struct.byte, ptr %ptr, i64 0, i32 1, i32 0
39 %add = load i8, ptr %a, align 4
42 %c = getelementptr inbounds %struct.byte, ptr %ptr, i64 0, i32 1
43 tail call void @bar_byte(ptr %c, i8 %add)
47 define void @store-pre-indexed-byte(ptr %ptr, i8 %val) nounwind {
48 ; CHECK-LABEL: store-pre-indexed-byte
49 ; CHECK: strb w{{[0-9]+}}, [x{{[0-9]+}}, #32]!
51 %a = getelementptr inbounds %struct.byte, ptr %ptr, i64 0, i32 1, i32 0
52 store i8 %val, ptr %a, align 4
55 %c = getelementptr inbounds %struct.byte, ptr %ptr, i64 0, i32 1
56 tail call void @bar_byte(ptr %c, i8 %val)
60 declare void @bar_halfword(ptr, i16)
62 define void @load-pre-indexed-halfword(ptr %ptr) nounwind {
63 ; CHECK-LABEL: load-pre-indexed-halfword
64 ; CHECK: ldrh w{{[0-9]+}}, [x{{[0-9]+}}, #32]!
66 %a = getelementptr inbounds %struct.halfword, ptr %ptr, i64 0, i32 1, i32 0
67 %add = load i16, ptr %a, align 4
70 %c = getelementptr inbounds %struct.halfword, ptr %ptr, i64 0, i32 1
71 tail call void @bar_halfword(ptr %c, i16 %add)
75 define void @store-pre-indexed-halfword(ptr %ptr, i16 %val) nounwind {
76 ; CHECK-LABEL: store-pre-indexed-halfword
77 ; CHECK: strh w{{[0-9]+}}, [x{{[0-9]+}}, #32]!
79 %a = getelementptr inbounds %struct.halfword, ptr %ptr, i64 0, i32 1, i32 0
80 store i16 %val, ptr %a, align 4
83 %c = getelementptr inbounds %struct.halfword, ptr %ptr, i64 0, i32 1
84 tail call void @bar_halfword(ptr %c, i16 %val)
88 declare void @bar_word(ptr, i32)
90 define void @load-pre-indexed-word(ptr %ptr) nounwind {
91 ; CHECK-LABEL: load-pre-indexed-word
92 ; CHECK: ldr w{{[0-9]+}}, [x{{[0-9]+}}, #32]!
94 %a = getelementptr inbounds %struct.word, ptr %ptr, i64 0, i32 1, i32 0
95 %add = load i32, ptr %a, align 4
98 %c = getelementptr inbounds %struct.word, ptr %ptr, i64 0, i32 1
99 tail call void @bar_word(ptr %c, i32 %add)
103 define void @store-pre-indexed-word(ptr %ptr, i32 %val) nounwind {
104 ; CHECK-LABEL: store-pre-indexed-word
105 ; CHECK: str w{{[0-9]+}}, [x{{[0-9]+}}, #32]!
107 %a = getelementptr inbounds %struct.word, ptr %ptr, i64 0, i32 1, i32 0
108 store i32 %val, ptr %a, align 4
111 %c = getelementptr inbounds %struct.word, ptr %ptr, i64 0, i32 1
112 tail call void @bar_word(ptr %c, i32 %val)
116 declare void @bar_doubleword(ptr, i64)
118 define void @load-pre-indexed-doubleword(ptr %ptr) nounwind {
119 ; CHECK-LABEL: load-pre-indexed-doubleword
120 ; CHECK: ldr x{{[0-9]+}}, [x{{[0-9]+}}, #32]!
122 %a = getelementptr inbounds %struct.doubleword, ptr %ptr, i64 0, i32 1, i32 0
123 %add = load i64, ptr %a, align 8
126 %c = getelementptr inbounds %struct.doubleword, ptr %ptr, i64 0, i32 1
127 tail call void @bar_doubleword(ptr %c, i64 %add)
131 define void @store-pre-indexed-doubleword(ptr %ptr, i64 %val) nounwind {
132 ; CHECK-LABEL: store-pre-indexed-doubleword
133 ; CHECK: str x{{[0-9]+}}, [x{{[0-9]+}}, #32]!
135 %a = getelementptr inbounds %struct.doubleword, ptr %ptr, i64 0, i32 1, i32 0
136 store i64 %val, ptr %a, align 8
139 %c = getelementptr inbounds %struct.doubleword, ptr %ptr, i64 0, i32 1
140 tail call void @bar_doubleword(ptr %c, i64 %val)
144 declare void @bar_quadword(ptr, fp128)
146 define void @load-pre-indexed-quadword(ptr %ptr) nounwind {
147 ; CHECK-LABEL: load-pre-indexed-quadword
148 ; CHECK: ldr q{{[0-9]+}}, [x{{[0-9]+}}, #32]!
150 %a = getelementptr inbounds %struct.quadword, ptr %ptr, i64 0, i32 1, i32 0
151 %add = load fp128, ptr %a, align 16
154 %c = getelementptr inbounds %struct.quadword, ptr %ptr, i64 0, i32 1
155 tail call void @bar_quadword(ptr %c, fp128 %add)
159 define void @store-pre-indexed-quadword(ptr %ptr, fp128 %val) nounwind {
160 ; CHECK-LABEL: store-pre-indexed-quadword
161 ; CHECK: str q{{[0-9]+}}, [x{{[0-9]+}}, #32]!
163 %a = getelementptr inbounds %struct.quadword, ptr %ptr, i64 0, i32 1, i32 0
164 store fp128 %val, ptr %a, align 16
167 %c = getelementptr inbounds %struct.quadword, ptr %ptr, i64 0, i32 1
168 tail call void @bar_quadword(ptr %c, fp128 %val)
172 declare void @bar_float(ptr, float)
174 define void @load-pre-indexed-float(ptr %ptr) nounwind {
175 ; CHECK-LABEL: load-pre-indexed-float
176 ; CHECK: ldr s{{[0-9]+}}, [x{{[0-9]+}}, #32]!
178 %a = getelementptr inbounds %struct.float, ptr %ptr, i64 0, i32 1, i32 0
179 %add = load float, ptr %a, align 4
182 %c = getelementptr inbounds %struct.float, ptr %ptr, i64 0, i32 1
183 tail call void @bar_float(ptr %c, float %add)
187 define void @store-pre-indexed-float(ptr %ptr, float %val) nounwind {
188 ; CHECK-LABEL: store-pre-indexed-float
189 ; CHECK: str s{{[0-9]+}}, [x{{[0-9]+}}, #32]!
191 %a = getelementptr inbounds %struct.float, ptr %ptr, i64 0, i32 1, i32 0
192 store float %val, ptr %a, align 4
195 %c = getelementptr inbounds %struct.float, ptr %ptr, i64 0, i32 1
196 tail call void @bar_float(ptr %c, float %val)
200 declare void @bar_double(ptr, double)
202 define void @load-pre-indexed-double(ptr %ptr) nounwind {
203 ; CHECK-LABEL: load-pre-indexed-double
204 ; CHECK: ldr d{{[0-9]+}}, [x{{[0-9]+}}, #32]!
206 %a = getelementptr inbounds %struct.double, ptr %ptr, i64 0, i32 1, i32 0
207 %add = load double, ptr %a, align 8
210 %c = getelementptr inbounds %struct.double, ptr %ptr, i64 0, i32 1
211 tail call void @bar_double(ptr %c, double %add)
215 define void @store-pre-indexed-double(ptr %ptr, double %val) nounwind {
216 ; CHECK-LABEL: store-pre-indexed-double
217 ; CHECK: str d{{[0-9]+}}, [x{{[0-9]+}}, #32]!
219 %a = getelementptr inbounds %struct.double, ptr %ptr, i64 0, i32 1, i32 0
220 store double %val, ptr %a, align 8
223 %c = getelementptr inbounds %struct.double, ptr %ptr, i64 0, i32 1
224 tail call void @bar_double(ptr %c, double %val)
228 ; Check the following transform:
230 ; (ldp|stp) w1, w2 [x0, #32]
234 ; (ldp|stp) w1, w2, [x0, #32]!
237 define void @load-pair-pre-indexed-word(ptr %ptr) nounwind {
238 ; CHECK-LABEL: load-pair-pre-indexed-word
239 ; CHECK: ldp w{{[0-9]+}}, w{{[0-9]+}}, [x0, #32]!
240 ; CHECK-NOT: add x0, x0, #32
242 %a = getelementptr inbounds %struct.word, ptr %ptr, i64 0, i32 1, i32 0
243 %a1 = load i32, ptr %a, align 4
244 %b = getelementptr inbounds %struct.word, ptr %ptr, i64 0, i32 1, i32 1
245 %b1 = load i32, ptr %b, align 4
246 %add = add i32 %a1, %b1
249 %c = getelementptr inbounds %struct.word, ptr %ptr, i64 0, i32 1
250 tail call void @bar_word(ptr %c, i32 %add)
254 define void @store-pair-pre-indexed-word(ptr %ptr, i32 %val) nounwind {
255 ; CHECK-LABEL: store-pair-pre-indexed-word
256 ; CHECK: stp w{{[0-9]+}}, w{{[0-9]+}}, [x0, #32]!
257 ; CHECK-NOT: add x0, x0, #32
259 %a = getelementptr inbounds %struct.word, ptr %ptr, i64 0, i32 1, i32 0
260 store i32 %val, ptr %a, align 4
261 %b = getelementptr inbounds %struct.word, ptr %ptr, i64 0, i32 1, i32 1
262 store i32 %val, ptr %b, align 4
265 %c = getelementptr inbounds %struct.word, ptr %ptr, i64 0, i32 1
266 tail call void @bar_word(ptr %c, i32 %val)
270 ; Check the following transform:
278 ; with X being either w0, x0, s0, d0 or q0.
280 %pre.struct.i32 = type { i32, i32, i32, i32, i32}
281 %pre.struct.i64 = type { i32, i64, i64, i64, i64}
282 %pre.struct.i128 = type { i32, <2 x i64>, <2 x i64>, <2 x i64>}
283 %pre.struct.float = type { i32, float, float, float}
284 %pre.struct.double = type { i32, double, double, double}
286 define i32 @load-pre-indexed-word2(ptr %this, i1 %cond,
287 ptr %load2) nounwind {
288 ; CHECK-LABEL: load-pre-indexed-word2
289 ; CHECK: ldr w{{[0-9]+}}, [x{{[0-9]+}}, #4]!
290 br i1 %cond, label %if.then, label %if.end
292 %load1 = load ptr, ptr %this
293 %gep1 = getelementptr inbounds %pre.struct.i32, ptr %load1, i64 0, i32 1
296 %gep2 = getelementptr inbounds %pre.struct.i32, ptr %load2, i64 0, i32 2
299 %retptr = phi ptr [ %gep1, %if.then ], [ %gep2, %if.end ]
300 %ret = load i32, ptr %retptr
304 define i64 @load-pre-indexed-doubleword2(ptr %this, i1 %cond,
305 ptr %load2) nounwind {
306 ; CHECK-LABEL: load-pre-indexed-doubleword2
307 ; CHECK: ldr x{{[0-9]+}}, [x{{[0-9]+}}, #8]!
308 br i1 %cond, label %if.then, label %if.end
310 %load1 = load ptr, ptr %this
311 %gep1 = getelementptr inbounds %pre.struct.i64, ptr %load1, i64 0, i32 1
314 %gep2 = getelementptr inbounds %pre.struct.i64, ptr %load2, i64 0, i32 2
317 %retptr = phi ptr [ %gep1, %if.then ], [ %gep2, %if.end ]
318 %ret = load i64, ptr %retptr
322 define <2 x i64> @load-pre-indexed-quadword2(ptr %this, i1 %cond,
323 ptr %load2) nounwind {
324 ; CHECK-LABEL: load-pre-indexed-quadword2
325 ; CHECK: ldr q{{[0-9]+}}, [x{{[0-9]+}}, #16]!
326 br i1 %cond, label %if.then, label %if.end
328 %load1 = load ptr, ptr %this
329 %gep1 = getelementptr inbounds %pre.struct.i128, ptr %load1, i64 0, i32 1
332 %gep2 = getelementptr inbounds %pre.struct.i128, ptr %load2, i64 0, i32 2
335 %retptr = phi ptr [ %gep1, %if.then ], [ %gep2, %if.end ]
336 %ret = load <2 x i64>, ptr %retptr
340 define float @load-pre-indexed-float2(ptr %this, i1 %cond,
341 ptr %load2) nounwind {
342 ; CHECK-LABEL: load-pre-indexed-float2
343 ; CHECK: ldr s{{[0-9]+}}, [x{{[0-9]+}}, #4]!
344 br i1 %cond, label %if.then, label %if.end
346 %load1 = load ptr, ptr %this
347 %gep1 = getelementptr inbounds %pre.struct.float, ptr %load1, i64 0, i32 1
350 %gep2 = getelementptr inbounds %pre.struct.float, ptr %load2, i64 0, i32 2
353 %retptr = phi ptr [ %gep1, %if.then ], [ %gep2, %if.end ]
354 %ret = load float, ptr %retptr
358 define double @load-pre-indexed-double2(ptr %this, i1 %cond,
359 ptr %load2) nounwind {
360 ; CHECK-LABEL: load-pre-indexed-double2
361 ; CHECK: ldr d{{[0-9]+}}, [x{{[0-9]+}}, #8]!
362 br i1 %cond, label %if.then, label %if.end
364 %load1 = load ptr, ptr %this
365 %gep1 = getelementptr inbounds %pre.struct.double, ptr %load1, i64 0, i32 1
368 %gep2 = getelementptr inbounds %pre.struct.double, ptr %load2, i64 0, i32 2
371 %retptr = phi ptr [ %gep1, %if.then ], [ %gep2, %if.end ]
372 %ret = load double, ptr %retptr
376 define i32 @load-pre-indexed-word3(ptr %this, i1 %cond,
377 ptr %load2) nounwind {
378 ; CHECK-LABEL: load-pre-indexed-word3
379 ; CHECK: ldr w{{[0-9]+}}, [x{{[0-9]+}}, #12]!
380 br i1 %cond, label %if.then, label %if.end
382 %load1 = load ptr, ptr %this
383 %gep1 = getelementptr inbounds %pre.struct.i32, ptr %load1, i64 0, i32 3
386 %gep2 = getelementptr inbounds %pre.struct.i32, ptr %load2, i64 0, i32 4
389 %retptr = phi ptr [ %gep1, %if.then ], [ %gep2, %if.end ]
390 %ret = load i32, ptr %retptr
394 define i64 @load-pre-indexed-doubleword3(ptr %this, i1 %cond,
395 ptr %load2) nounwind {
396 ; CHECK-LABEL: load-pre-indexed-doubleword3
397 ; CHECK: ldr x{{[0-9]+}}, [x{{[0-9]+}}, #16]!
398 br i1 %cond, label %if.then, label %if.end
400 %load1 = load ptr, ptr %this
401 %gep1 = getelementptr inbounds %pre.struct.i64, ptr %load1, i64 0, i32 2
404 %gep2 = getelementptr inbounds %pre.struct.i64, ptr %load2, i64 0, i32 3
407 %retptr = phi ptr [ %gep1, %if.then ], [ %gep2, %if.end ]
408 %ret = load i64, ptr %retptr
412 define <2 x i64> @load-pre-indexed-quadword3(ptr %this, i1 %cond,
413 ptr %load2) nounwind {
414 ; CHECK-LABEL: load-pre-indexed-quadword3
415 ; CHECK: ldr q{{[0-9]+}}, [x{{[0-9]+}}, #32]!
416 br i1 %cond, label %if.then, label %if.end
418 %load1 = load ptr, ptr %this
419 %gep1 = getelementptr inbounds %pre.struct.i128, ptr %load1, i64 0, i32 2
422 %gep2 = getelementptr inbounds %pre.struct.i128, ptr %load2, i64 0, i32 3
425 %retptr = phi ptr [ %gep1, %if.then ], [ %gep2, %if.end ]
426 %ret = load <2 x i64>, ptr %retptr
430 define float @load-pre-indexed-float3(ptr %this, i1 %cond,
431 ptr %load2) nounwind {
432 ; CHECK-LABEL: load-pre-indexed-float3
433 ; CHECK: ldr s{{[0-9]+}}, [x{{[0-9]+}}, #8]!
434 br i1 %cond, label %if.then, label %if.end
436 %load1 = load ptr, ptr %this
437 %gep1 = getelementptr inbounds %pre.struct.float, ptr %load1, i64 0, i32 2
440 %gep2 = getelementptr inbounds %pre.struct.float, ptr %load2, i64 0, i32 3
443 %retptr = phi ptr [ %gep1, %if.then ], [ %gep2, %if.end ]
444 %ret = load float, ptr %retptr
448 define double @load-pre-indexed-double3(ptr %this, i1 %cond,
449 ptr %load2) nounwind {
450 ; CHECK-LABEL: load-pre-indexed-double3
451 ; CHECK: ldr d{{[0-9]+}}, [x{{[0-9]+}}, #16]!
452 br i1 %cond, label %if.then, label %if.end
454 %load1 = load ptr, ptr %this
455 %gep1 = getelementptr inbounds %pre.struct.double, ptr %load1, i64 0, i32 2
458 %gep2 = getelementptr inbounds %pre.struct.double, ptr %load2, i64 0, i32 3
461 %retptr = phi ptr [ %gep1, %if.then ], [ %gep2, %if.end ]
462 %ret = load double, ptr %retptr
466 ; Check the following transform:
474 ; with X being either w0, x0, s0, d0 or q0.
476 define void @store-pre-indexed-word2(ptr %this, i1 %cond,
479 ; CHECK-LABEL: store-pre-indexed-word2
480 ; CHECK: str w{{[0-9]+}}, [x{{[0-9]+}}, #4]!
481 br i1 %cond, label %if.then, label %if.end
483 %load1 = load ptr, ptr %this
484 %gep1 = getelementptr inbounds %pre.struct.i32, ptr %load1, i64 0, i32 1
487 %gep2 = getelementptr inbounds %pre.struct.i32, ptr %load2, i64 0, i32 2
490 %retptr = phi ptr [ %gep1, %if.then ], [ %gep2, %if.end ]
491 store i32 %val, ptr %retptr
495 define void @store-pre-indexed-doubleword2(ptr %this, i1 %cond,
498 ; CHECK-LABEL: store-pre-indexed-doubleword2
499 ; CHECK: str x{{[0-9]+}}, [x{{[0-9]+}}, #8]!
500 br i1 %cond, label %if.then, label %if.end
502 %load1 = load ptr, ptr %this
503 %gep1 = getelementptr inbounds %pre.struct.i64, ptr %load1, i64 0, i32 1
506 %gep2 = getelementptr inbounds %pre.struct.i64, ptr %load2, i64 0, i32 2
509 %retptr = phi ptr [ %gep1, %if.then ], [ %gep2, %if.end ]
510 store i64 %val, ptr %retptr
514 define void @store-pre-indexed-quadword2(ptr %this, i1 %cond,
516 <2 x i64> %val) nounwind {
517 ; CHECK-LABEL: store-pre-indexed-quadword2
518 ; CHECK: str q{{[0-9]+}}, [x{{[0-9]+}}, #16]!
519 br i1 %cond, label %if.then, label %if.end
521 %load1 = load ptr, ptr %this
522 %gep1 = getelementptr inbounds %pre.struct.i128, ptr %load1, i64 0, i32 1
525 %gep2 = getelementptr inbounds %pre.struct.i128, ptr %load2, i64 0, i32 2
528 %retptr = phi ptr [ %gep1, %if.then ], [ %gep2, %if.end ]
529 store <2 x i64> %val, ptr %retptr
533 define void @store-pre-indexed-float2(ptr %this, i1 %cond,
535 float %val) nounwind {
536 ; CHECK-LABEL: store-pre-indexed-float2
537 ; CHECK: str s{{[0-9]+}}, [x{{[0-9]+}}, #4]!
538 br i1 %cond, label %if.then, label %if.end
540 %load1 = load ptr, ptr %this
541 %gep1 = getelementptr inbounds %pre.struct.float, ptr %load1, i64 0, i32 1
544 %gep2 = getelementptr inbounds %pre.struct.float, ptr %load2, i64 0, i32 2
547 %retptr = phi ptr [ %gep1, %if.then ], [ %gep2, %if.end ]
548 store float %val, ptr %retptr
552 define void @store-pre-indexed-double2(ptr %this, i1 %cond,
554 double %val) nounwind {
555 ; CHECK-LABEL: store-pre-indexed-double2
556 ; CHECK: str d{{[0-9]+}}, [x{{[0-9]+}}, #8]!
557 br i1 %cond, label %if.then, label %if.end
559 %load1 = load ptr, ptr %this
560 %gep1 = getelementptr inbounds %pre.struct.double, ptr %load1, i64 0, i32 1
563 %gep2 = getelementptr inbounds %pre.struct.double, ptr %load2, i64 0, i32 2
566 %retptr = phi ptr [ %gep1, %if.then ], [ %gep2, %if.end ]
567 store double %val, ptr %retptr
571 define void @store-pre-indexed-word3(ptr %this, i1 %cond,
574 ; CHECK-LABEL: store-pre-indexed-word3
575 ; CHECK: str w{{[0-9]+}}, [x{{[0-9]+}}, #12]!
576 br i1 %cond, label %if.then, label %if.end
578 %load1 = load ptr, ptr %this
579 %gep1 = getelementptr inbounds %pre.struct.i32, ptr %load1, i64 0, i32 3
582 %gep2 = getelementptr inbounds %pre.struct.i32, ptr %load2, i64 0, i32 4
585 %retptr = phi ptr [ %gep1, %if.then ], [ %gep2, %if.end ]
586 store i32 %val, ptr %retptr
590 define void @store-pre-indexed-doubleword3(ptr %this, i1 %cond,
593 ; CHECK-LABEL: store-pre-indexed-doubleword3
594 ; CHECK: str x{{[0-9]+}}, [x{{[0-9]+}}, #24]!
595 br i1 %cond, label %if.then, label %if.end
597 %load1 = load ptr, ptr %this
598 %gep1 = getelementptr inbounds %pre.struct.i64, ptr %load1, i64 0, i32 3
601 %gep2 = getelementptr inbounds %pre.struct.i64, ptr %load2, i64 0, i32 4
604 %retptr = phi ptr [ %gep1, %if.then ], [ %gep2, %if.end ]
605 store i64 %val, ptr %retptr
609 define void @store-pre-indexed-quadword3(ptr %this, i1 %cond,
611 <2 x i64> %val) nounwind {
612 ; CHECK-LABEL: store-pre-indexed-quadword3
613 ; CHECK: str q{{[0-9]+}}, [x{{[0-9]+}}, #32]!
614 br i1 %cond, label %if.then, label %if.end
616 %load1 = load ptr, ptr %this
617 %gep1 = getelementptr inbounds %pre.struct.i128, ptr %load1, i64 0, i32 2
620 %gep2 = getelementptr inbounds %pre.struct.i128, ptr %load2, i64 0, i32 3
623 %retptr = phi ptr [ %gep1, %if.then ], [ %gep2, %if.end ]
624 store <2 x i64> %val, ptr %retptr
628 define void @store-pre-indexed-float3(ptr %this, i1 %cond,
630 float %val) nounwind {
631 ; CHECK-LABEL: store-pre-indexed-float3
632 ; CHECK: str s{{[0-9]+}}, [x{{[0-9]+}}, #8]!
633 br i1 %cond, label %if.then, label %if.end
635 %load1 = load ptr, ptr %this
636 %gep1 = getelementptr inbounds %pre.struct.float, ptr %load1, i64 0, i32 2
639 %gep2 = getelementptr inbounds %pre.struct.float, ptr %load2, i64 0, i32 3
642 %retptr = phi ptr [ %gep1, %if.then ], [ %gep2, %if.end ]
643 store float %val, ptr %retptr
647 define void @store-pre-indexed-double3(ptr %this, i1 %cond,
649 double %val) nounwind {
650 ; CHECK-LABEL: store-pre-indexed-double3
651 ; CHECK: str d{{[0-9]+}}, [x{{[0-9]+}}, #16]!
652 br i1 %cond, label %if.then, label %if.end
654 %load1 = load ptr, ptr %this
655 %gep1 = getelementptr inbounds %pre.struct.double, ptr %load1, i64 0, i32 2
658 %gep2 = getelementptr inbounds %pre.struct.double, ptr %load2, i64 0, i32 3
661 %retptr = phi ptr [ %gep1, %if.then ], [ %gep2, %if.end ]
662 store double %val, ptr %retptr
666 ; Check the following transform:
674 ; with X being either w0, x0, s0, d0 or q0.
676 define void @load-post-indexed-byte(ptr %array, i64 %count) nounwind {
677 ; CHECK-LABEL: load-post-indexed-byte
678 ; CHECK: ldrb w{{[0-9]+}}, [x{{[0-9]+}}], #4
680 %gep1 = getelementptr i8, ptr %array, i64 2
684 %iv2 = phi ptr [ %gep3, %body ], [ %gep1, %entry ]
685 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
686 %gep2 = getelementptr i8, ptr %iv2, i64 -1
687 %load = load i8, ptr %gep2
688 call void @use-byte(i8 %load)
689 %load2 = load i8, ptr %iv2
690 call void @use-byte(i8 %load2)
691 %iv.next = add i64 %iv, -4
692 %gep3 = getelementptr i8, ptr %iv2, i64 4
693 %cond = icmp eq i64 %iv.next, 0
694 br i1 %cond, label %exit, label %body
700 define void @load-post-indexed-halfword(ptr %array, i64 %count) nounwind {
701 ; CHECK-LABEL: load-post-indexed-halfword
702 ; CHECK: ldrh w{{[0-9]+}}, [x{{[0-9]+}}], #8
704 %gep1 = getelementptr i16, ptr %array, i64 2
708 %iv2 = phi ptr [ %gep3, %body ], [ %gep1, %entry ]
709 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
710 %gep2 = getelementptr i16, ptr %iv2, i64 -1
711 %load = load i16, ptr %gep2
712 call void @use-halfword(i16 %load)
713 %load2 = load i16, ptr %iv2
714 call void @use-halfword(i16 %load2)
715 %iv.next = add i64 %iv, -4
716 %gep3 = getelementptr i16, ptr %iv2, i64 4
717 %cond = icmp eq i64 %iv.next, 0
718 br i1 %cond, label %exit, label %body
724 define void @load-post-indexed-word(ptr %array, i64 %count) nounwind {
725 ; CHECK-LABEL: load-post-indexed-word
726 ; CHECK: ldr w{{[0-9]+}}, [x{{[0-9]+}}], #16
728 %gep1 = getelementptr i32, ptr %array, i64 2
732 %iv2 = phi ptr [ %gep3, %body ], [ %gep1, %entry ]
733 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
734 %gep2 = getelementptr i32, ptr %iv2, i64 -1
735 %load = load i32, ptr %gep2
736 call void @use-word(i32 %load)
737 %load2 = load i32, ptr %iv2
738 call void @use-word(i32 %load2)
739 %iv.next = add i64 %iv, -4
740 %gep3 = getelementptr i32, ptr %iv2, i64 4
741 %cond = icmp eq i64 %iv.next, 0
742 br i1 %cond, label %exit, label %body
748 define void @load-post-indexed-doubleword(ptr %array, i64 %count) nounwind {
749 ; CHECK-LABEL: load-post-indexed-doubleword
750 ; CHECK: ldr x{{[0-9]+}}, [x{{[0-9]+}}], #32
752 %gep1 = getelementptr i64, ptr %array, i64 2
756 %iv2 = phi ptr [ %gep3, %body ], [ %gep1, %entry ]
757 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
758 %gep2 = getelementptr i64, ptr %iv2, i64 -1
759 %load = load i64, ptr %gep2
760 call void @use-doubleword(i64 %load)
761 %load2 = load i64, ptr %iv2
762 call void @use-doubleword(i64 %load2)
763 %iv.next = add i64 %iv, -4
764 %gep3 = getelementptr i64, ptr %iv2, i64 4
765 %cond = icmp eq i64 %iv.next, 0
766 br i1 %cond, label %exit, label %body
772 define void @load-post-indexed-quadword(ptr %array, i64 %count) nounwind {
773 ; CHECK-LABEL: load-post-indexed-quadword
774 ; CHECK: ldr q{{[0-9]+}}, [x{{[0-9]+}}], #64
776 %gep1 = getelementptr <2 x i64>, ptr %array, i64 2
780 %iv2 = phi ptr [ %gep3, %body ], [ %gep1, %entry ]
781 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
782 %gep2 = getelementptr <2 x i64>, ptr %iv2, i64 -1
783 %load = load <2 x i64>, ptr %gep2
784 call void @use-quadword(<2 x i64> %load)
785 %load2 = load <2 x i64>, ptr %iv2
786 call void @use-quadword(<2 x i64> %load2)
787 %iv.next = add i64 %iv, -4
788 %gep3 = getelementptr <2 x i64>, ptr %iv2, i64 4
789 %cond = icmp eq i64 %iv.next, 0
790 br i1 %cond, label %exit, label %body
796 define void @load-post-indexed-float(ptr %array, i64 %count) nounwind {
797 ; CHECK-LABEL: load-post-indexed-float
798 ; CHECK: ldr s{{[0-9]+}}, [x{{[0-9]+}}], #16
800 %gep1 = getelementptr float, ptr %array, i64 2
804 %iv2 = phi ptr [ %gep3, %body ], [ %gep1, %entry ]
805 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
806 %gep2 = getelementptr float, ptr %iv2, i64 -1
807 %load = load float, ptr %gep2
808 call void @use-float(float %load)
809 %load2 = load float, ptr %iv2
810 call void @use-float(float %load2)
811 %iv.next = add i64 %iv, -4
812 %gep3 = getelementptr float, ptr %iv2, i64 4
813 %cond = icmp eq i64 %iv.next, 0
814 br i1 %cond, label %exit, label %body
820 define void @load-post-indexed-double(ptr %array, i64 %count) nounwind {
821 ; CHECK-LABEL: load-post-indexed-double
822 ; CHECK: ldr d{{[0-9]+}}, [x{{[0-9]+}}], #32
824 %gep1 = getelementptr double, ptr %array, i64 2
828 %iv2 = phi ptr [ %gep3, %body ], [ %gep1, %entry ]
829 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
830 %gep2 = getelementptr double, ptr %iv2, i64 -1
831 %load = load double, ptr %gep2
832 call void @use-double(double %load)
833 %load2 = load double, ptr %iv2
834 call void @use-double(double %load2)
835 %iv.next = add i64 %iv, -4
836 %gep3 = getelementptr double, ptr %iv2, i64 4
837 %cond = icmp eq i64 %iv.next, 0
838 br i1 %cond, label %exit, label %body
844 ; Check the following transform:
852 ; with X being either w0, x0, s0, d0 or q0.
854 define void @store-post-indexed-byte(ptr %array, i64 %count, i8 %val) nounwind {
855 ; CHECK-LABEL: store-post-indexed-byte
856 ; CHECK: strb w{{[0-9]+}}, [x{{[0-9]+}}], #4
858 %gep1 = getelementptr i8, ptr %array, i64 2
862 %iv2 = phi ptr [ %gep3, %body ], [ %gep1, %entry ]
863 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
864 %gep2 = getelementptr i8, ptr %iv2, i64 -1
865 %load = load i8, ptr %gep2
866 call void @use-byte(i8 %load)
867 store i8 %val, ptr %iv2
868 %iv.next = add i64 %iv, -4
869 %gep3 = getelementptr i8, ptr %iv2, i64 4
870 %cond = icmp eq i64 %iv.next, 0
871 br i1 %cond, label %exit, label %body
877 define void @store-post-indexed-halfword(ptr %array, i64 %count, i16 %val) nounwind {
878 ; CHECK-LABEL: store-post-indexed-halfword
879 ; CHECK: strh w{{[0-9]+}}, [x{{[0-9]+}}], #8
881 %gep1 = getelementptr i16, ptr %array, i64 2
885 %iv2 = phi ptr [ %gep3, %body ], [ %gep1, %entry ]
886 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
887 %gep2 = getelementptr i16, ptr %iv2, i64 -1
888 %load = load i16, ptr %gep2
889 call void @use-halfword(i16 %load)
890 store i16 %val, ptr %iv2
891 %iv.next = add i64 %iv, -4
892 %gep3 = getelementptr i16, ptr %iv2, i64 4
893 %cond = icmp eq i64 %iv.next, 0
894 br i1 %cond, label %exit, label %body
900 define void @store-post-indexed-word(ptr %array, i64 %count, i32 %val) nounwind {
901 ; CHECK-LABEL: store-post-indexed-word
902 ; CHECK: str w{{[0-9]+}}, [x{{[0-9]+}}], #16
904 %gep1 = getelementptr i32, ptr %array, i64 2
908 %iv2 = phi ptr [ %gep3, %body ], [ %gep1, %entry ]
909 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
910 %gep2 = getelementptr i32, ptr %iv2, i64 -1
911 %load = load i32, ptr %gep2
912 call void @use-word(i32 %load)
913 store i32 %val, ptr %iv2
914 %iv.next = add i64 %iv, -4
915 %gep3 = getelementptr i32, ptr %iv2, i64 4
916 %cond = icmp eq i64 %iv.next, 0
917 br i1 %cond, label %exit, label %body
923 define void @store-post-indexed-doubleword(ptr %array, i64 %count, i64 %val) nounwind {
924 ; CHECK-LABEL: store-post-indexed-doubleword
925 ; CHECK: str x{{[0-9]+}}, [x{{[0-9]+}}], #32
927 %gep1 = getelementptr i64, ptr %array, i64 2
931 %iv2 = phi ptr [ %gep3, %body ], [ %gep1, %entry ]
932 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
933 %gep2 = getelementptr i64, ptr %iv2, i64 -1
934 %load = load i64, ptr %gep2
935 call void @use-doubleword(i64 %load)
936 store i64 %val, ptr %iv2
937 %iv.next = add i64 %iv, -4
938 %gep3 = getelementptr i64, ptr %iv2, i64 4
939 %cond = icmp eq i64 %iv.next, 0
940 br i1 %cond, label %exit, label %body
946 define void @store-post-indexed-quadword(ptr %array, i64 %count, <2 x i64> %val) nounwind {
947 ; CHECK-LABEL: store-post-indexed-quadword
948 ; CHECK: str q{{[0-9]+}}, [x{{[0-9]+}}], #64
950 %gep1 = getelementptr <2 x i64>, ptr %array, i64 2
954 %iv2 = phi ptr [ %gep3, %body ], [ %gep1, %entry ]
955 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
956 %gep2 = getelementptr <2 x i64>, ptr %iv2, i64 -1
957 %load = load <2 x i64>, ptr %gep2
958 call void @use-quadword(<2 x i64> %load)
959 store <2 x i64> %val, ptr %iv2
960 %iv.next = add i64 %iv, -4
961 %gep3 = getelementptr <2 x i64>, ptr %iv2, i64 4
962 %cond = icmp eq i64 %iv.next, 0
963 br i1 %cond, label %exit, label %body
969 define void @store-post-indexed-float(ptr %array, i64 %count, float %val) nounwind {
970 ; CHECK-LABEL: store-post-indexed-float
971 ; CHECK: str s{{[0-9]+}}, [x{{[0-9]+}}], #16
973 %gep1 = getelementptr float, ptr %array, i64 2
977 %iv2 = phi ptr [ %gep3, %body ], [ %gep1, %entry ]
978 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
979 %gep2 = getelementptr float, ptr %iv2, i64 -1
980 %load = load float, ptr %gep2
981 call void @use-float(float %load)
982 store float %val, ptr %iv2
983 %iv.next = add i64 %iv, -4
984 %gep3 = getelementptr float, ptr %iv2, i64 4
985 %cond = icmp eq i64 %iv.next, 0
986 br i1 %cond, label %exit, label %body
992 define void @store-post-indexed-double(ptr %array, i64 %count, double %val) nounwind {
993 ; CHECK-LABEL: store-post-indexed-double
994 ; CHECK: str d{{[0-9]+}}, [x{{[0-9]+}}], #32
996 %gep1 = getelementptr double, ptr %array, i64 2
1000 %iv2 = phi ptr [ %gep3, %body ], [ %gep1, %entry ]
1001 %iv = phi i64 [ %iv.next, %body ], [ %count, %entry ]
1002 %gep2 = getelementptr double, ptr %iv2, i64 -1
1003 %load = load double, ptr %gep2
1004 call void @use-double(double %load)
1005 store double %val, ptr %iv2
1006 %iv.next = add i64 %iv, -4
1007 %gep3 = getelementptr double, ptr %iv2, i64 4
1008 %cond = icmp eq i64 %iv.next, 0
1009 br i1 %cond, label %exit, label %body
1015 declare void @use-byte(i8)
1016 declare void @use-halfword(i16)
1017 declare void @use-word(i32)
1018 declare void @use-doubleword(i64)
1019 declare void @use-quadword(<2 x i64>)
1020 declare void @use-float(float)
1021 declare void @use-double(double)
1023 ; Check the following transform:
1029 ; stp w0, [x20], #32
1031 define void @store-pair-post-indexed-word() nounwind {
1032 ; CHECK-LABEL: store-pair-post-indexed-word
1033 ; CHECK: stp w{{[0-9]+}}, w{{[0-9]+}}, [sp], #16
1035 %src = alloca { i32, i32 }, align 8
1036 %dst = alloca { i32, i32 }, align 8
1038 %src.realp = getelementptr inbounds { i32, i32 }, ptr %src, i32 0, i32 0
1039 %src.real = load i32, ptr %src.realp
1040 %src.imagp = getelementptr inbounds { i32, i32 }, ptr %src, i32 0, i32 1
1041 %src.imag = load i32, ptr %src.imagp
1043 %dst.realp = getelementptr inbounds { i32, i32 }, ptr %dst, i32 0, i32 0
1044 %dst.imagp = getelementptr inbounds { i32, i32 }, ptr %dst, i32 0, i32 1
1045 store i32 %src.real, ptr %dst.realp
1046 store i32 %src.imag, ptr %dst.imagp
1050 define void @store-pair-post-indexed-doubleword() nounwind {
1051 ; CHECK-LABEL: store-pair-post-indexed-doubleword
1052 ; CHECK: stp x{{[0-9]+}}, x{{[0-9]+}}, [sp], #32
1054 %src = alloca { i64, i64 }, align 8
1055 %dst = alloca { i64, i64 }, align 8
1057 %src.realp = getelementptr inbounds { i64, i64 }, ptr %src, i32 0, i32 0
1058 %src.real = load i64, ptr %src.realp
1059 %src.imagp = getelementptr inbounds { i64, i64 }, ptr %src, i32 0, i32 1
1060 %src.imag = load i64, ptr %src.imagp
1062 %dst.realp = getelementptr inbounds { i64, i64 }, ptr %dst, i32 0, i32 0
1063 %dst.imagp = getelementptr inbounds { i64, i64 }, ptr %dst, i32 0, i32 1
1064 store i64 %src.real, ptr %dst.realp
1065 store i64 %src.imag, ptr %dst.imagp
1069 define void @store-pair-post-indexed-float() nounwind {
1070 ; CHECK-LABEL: store-pair-post-indexed-float
1071 ; CHECK: stp s{{[0-9]+}}, s{{[0-9]+}}, [sp], #16
1073 %src = alloca { float, float }, align 8
1074 %dst = alloca { float, float }, align 8
1076 %src.realp = getelementptr inbounds { float, float }, ptr %src, i32 0, i32 0
1077 %src.real = load float, ptr %src.realp
1078 %src.imagp = getelementptr inbounds { float, float }, ptr %src, i32 0, i32 1
1079 %src.imag = load float, ptr %src.imagp
1081 %dst.realp = getelementptr inbounds { float, float }, ptr %dst, i32 0, i32 0
1082 %dst.imagp = getelementptr inbounds { float, float }, ptr %dst, i32 0, i32 1
1083 store float %src.real, ptr %dst.realp
1084 store float %src.imag, ptr %dst.imagp
1088 define void @store-pair-post-indexed-double() nounwind {
1089 ; CHECK-LABEL: store-pair-post-indexed-double
1090 ; CHECK: stp d{{[0-9]+}}, d{{[0-9]+}}, [sp], #32
1092 %src = alloca { double, double }, align 8
1093 %dst = alloca { double, double }, align 8
1095 %src.realp = getelementptr inbounds { double, double }, ptr %src, i32 0, i32 0
1096 %src.real = load double, ptr %src.realp
1097 %src.imagp = getelementptr inbounds { double, double }, ptr %src, i32 0, i32 1
1098 %src.imag = load double, ptr %src.imagp
1100 %dst.realp = getelementptr inbounds { double, double }, ptr %dst, i32 0, i32 0
1101 %dst.imagp = getelementptr inbounds { double, double }, ptr %dst, i32 0, i32 1
1102 store double %src.real, ptr %dst.realp
1103 store double %src.imag, ptr %dst.imagp
1107 ; Check the following transform:
1109 ; (ldr|str) X, [x20]
1113 ; (ldr|str) X, [x20], #-16
1115 ; with X being either w0, x0, s0, d0 or q0.
1117 define void @post-indexed-sub-word(ptr %a, ptr %b, i64 %count) nounwind {
1118 ; CHECK-LABEL: post-indexed-sub-word
1119 ; CHECK: ldr w{{[0-9]+}}, [x{{[0-9]+}}], #-8
1120 ; CHECK: str w{{[0-9]+}}, [x{{[0-9]+}}], #-8
1123 %phi1 = phi ptr [ %gep4, %for.body ], [ %b, %0 ]
1124 %phi2 = phi ptr [ %gep3, %for.body ], [ %a, %0 ]
1125 %i = phi i64 [ %dec.i, %for.body], [ %count, %0 ]
1126 %gep1 = getelementptr i32, ptr %phi1, i64 -1
1127 %load1 = load i32, ptr %gep1
1128 %gep2 = getelementptr i32, ptr %phi2, i64 -1
1129 store i32 %load1, ptr %gep2
1130 %load2 = load i32, ptr %phi1
1131 store i32 %load2, ptr %phi2
1132 %dec.i = add nsw i64 %i, -1
1133 %gep3 = getelementptr i32, ptr %phi2, i64 -2
1134 %gep4 = getelementptr i32, ptr %phi1, i64 -2
1135 %cond = icmp sgt i64 %dec.i, 0
1136 br i1 %cond, label %for.body, label %end
1141 define void @post-indexed-sub-doubleword(ptr %a, ptr %b, i64 %count) nounwind {
1142 ; CHECK-LABEL: post-indexed-sub-doubleword
1143 ; CHECK: ldr x{{[0-9]+}}, [x{{[0-9]+}}], #-16
1144 ; CHECK: str x{{[0-9]+}}, [x{{[0-9]+}}], #-16
1147 %phi1 = phi ptr [ %gep4, %for.body ], [ %b, %0 ]
1148 %phi2 = phi ptr [ %gep3, %for.body ], [ %a, %0 ]
1149 %i = phi i64 [ %dec.i, %for.body], [ %count, %0 ]
1150 %gep1 = getelementptr i64, ptr %phi1, i64 -1
1151 %load1 = load i64, ptr %gep1
1152 %gep2 = getelementptr i64, ptr %phi2, i64 -1
1153 store i64 %load1, ptr %gep2
1154 %load2 = load i64, ptr %phi1
1155 store i64 %load2, ptr %phi2
1156 %dec.i = add nsw i64 %i, -1
1157 %gep3 = getelementptr i64, ptr %phi2, i64 -2
1158 %gep4 = getelementptr i64, ptr %phi1, i64 -2
1159 %cond = icmp sgt i64 %dec.i, 0
1160 br i1 %cond, label %for.body, label %end
1165 define void @post-indexed-sub-quadword(ptr %a, ptr %b, i64 %count) nounwind {
1166 ; CHECK-LABEL: post-indexed-sub-quadword
1167 ; CHECK: ldr q{{[0-9]+}}, [x{{[0-9]+}}], #-32
1168 ; CHECK: str q{{[0-9]+}}, [x{{[0-9]+}}], #-32
1171 %phi1 = phi ptr [ %gep4, %for.body ], [ %b, %0 ]
1172 %phi2 = phi ptr [ %gep3, %for.body ], [ %a, %0 ]
1173 %i = phi i64 [ %dec.i, %for.body], [ %count, %0 ]
1174 %gep1 = getelementptr <2 x i64>, ptr %phi1, i64 -1
1175 %load1 = load <2 x i64>, ptr %gep1
1176 %gep2 = getelementptr <2 x i64>, ptr %phi2, i64 -1
1177 store <2 x i64> %load1, ptr %gep2
1178 %load2 = load <2 x i64>, ptr %phi1
1179 store <2 x i64> %load2, ptr %phi2
1180 %dec.i = add nsw i64 %i, -1
1181 %gep3 = getelementptr <2 x i64>, ptr %phi2, i64 -2
1182 %gep4 = getelementptr <2 x i64>, ptr %phi1, i64 -2
1183 %cond = icmp sgt i64 %dec.i, 0
1184 br i1 %cond, label %for.body, label %end
1189 define void @post-indexed-sub-float(ptr %a, ptr %b, i64 %count) nounwind {
1190 ; CHECK-LABEL: post-indexed-sub-float
1191 ; CHECK: ldr s{{[0-9]+}}, [x{{[0-9]+}}], #-8
1192 ; CHECK: str s{{[0-9]+}}, [x{{[0-9]+}}], #-8
1195 %phi1 = phi ptr [ %gep4, %for.body ], [ %b, %0 ]
1196 %phi2 = phi ptr [ %gep3, %for.body ], [ %a, %0 ]
1197 %i = phi i64 [ %dec.i, %for.body], [ %count, %0 ]
1198 %gep1 = getelementptr float, ptr %phi1, i64 -1
1199 %load1 = load float, ptr %gep1
1200 %gep2 = getelementptr float, ptr %phi2, i64 -1
1201 store float %load1, ptr %gep2
1202 %load2 = load float, ptr %phi1
1203 store float %load2, ptr %phi2
1204 %dec.i = add nsw i64 %i, -1
1205 %gep3 = getelementptr float, ptr %phi2, i64 -2
1206 %gep4 = getelementptr float, ptr %phi1, i64 -2
1207 %cond = icmp sgt i64 %dec.i, 0
1208 br i1 %cond, label %for.body, label %end
1213 define void @post-indexed-sub-double(ptr %a, ptr %b, i64 %count) nounwind {
1214 ; CHECK-LABEL: post-indexed-sub-double
1215 ; CHECK: ldr d{{[0-9]+}}, [x{{[0-9]+}}], #-16
1216 ; CHECK: str d{{[0-9]+}}, [x{{[0-9]+}}], #-16
1219 %phi1 = phi ptr [ %gep4, %for.body ], [ %b, %0 ]
1220 %phi2 = phi ptr [ %gep3, %for.body ], [ %a, %0 ]
1221 %i = phi i64 [ %dec.i, %for.body], [ %count, %0 ]
1222 %gep1 = getelementptr double, ptr %phi1, i64 -1
1223 %load1 = load double, ptr %gep1
1224 %gep2 = getelementptr double, ptr %phi2, i64 -1
1225 store double %load1, ptr %gep2
1226 %load2 = load double, ptr %phi1
1227 store double %load2, ptr %phi2
1228 %dec.i = add nsw i64 %i, -1
1229 %gep3 = getelementptr double, ptr %phi2, i64 -2
1230 %gep4 = getelementptr double, ptr %phi1, i64 -2
1231 %cond = icmp sgt i64 %dec.i, 0
1232 br i1 %cond, label %for.body, label %end
1237 define void @post-indexed-sub-doubleword-offset-min(ptr %a, ptr %b, i64 %count) nounwind {
1238 ; CHECK-LABEL: post-indexed-sub-doubleword-offset-min
1239 ; CHECK: ldr x{{[0-9]+}}, [x{{[0-9]+}}], #-256
1240 ; CHECK: str x{{[0-9]+}}, [x{{[0-9]+}}], #-256
1243 %phi1 = phi ptr [ %gep4, %for.body ], [ %b, %0 ]
1244 %phi2 = phi ptr [ %gep3, %for.body ], [ %a, %0 ]
1245 %i = phi i64 [ %dec.i, %for.body], [ %count, %0 ]
1246 %gep1 = getelementptr i64, ptr %phi1, i64 1
1247 %load1 = load i64, ptr %gep1
1248 %gep2 = getelementptr i64, ptr %phi2, i64 1
1249 store i64 %load1, ptr %gep2
1250 %load2 = load i64, ptr %phi1
1251 store i64 %load2, ptr %phi2
1252 %dec.i = add nsw i64 %i, -1
1253 %gep3 = getelementptr i64, ptr %phi2, i64 -32
1254 %gep4 = getelementptr i64, ptr %phi1, i64 -32
1255 %cond = icmp sgt i64 %dec.i, 0
1256 br i1 %cond, label %for.body, label %end
1261 define void @post-indexed-doubleword-offset-out-of-range(ptr %a, ptr %b, i64 %count) nounwind {
1262 ; CHECK-LABEL: post-indexed-doubleword-offset-out-of-range
1263 ; CHECK: ldr x{{[0-9]+}}, [x{{[0-9]+}}]
1264 ; CHECK: add x{{[0-9]+}}, x{{[0-9]+}}, #256
1265 ; CHECK: str x{{[0-9]+}}, [x{{[0-9]+}}]
1266 ; CHECK: add x{{[0-9]+}}, x{{[0-9]+}}, #256
1270 %phi1 = phi ptr [ %gep4, %for.body ], [ %b, %0 ]
1271 %phi2 = phi ptr [ %gep3, %for.body ], [ %a, %0 ]
1272 %i = phi i64 [ %dec.i, %for.body], [ %count, %0 ]
1273 %gep1 = getelementptr i64, ptr %phi1, i64 1
1274 %load1 = load i64, ptr %gep1
1275 %gep2 = getelementptr i64, ptr %phi2, i64 1
1276 store i64 %load1, ptr %gep2
1277 %load2 = load i64, ptr %phi1
1278 store i64 %load2, ptr %phi2
1279 %dec.i = add nsw i64 %i, -1
1280 %gep3 = getelementptr i64, ptr %phi2, i64 32
1281 %gep4 = getelementptr i64, ptr %phi1, i64 32
1282 %cond = icmp sgt i64 %dec.i, 0
1283 br i1 %cond, label %for.body, label %end
1288 define void @post-indexed-paired-min-offset(ptr %a, ptr %b, i64 %count) nounwind {
1289 ; CHECK-LABEL: post-indexed-paired-min-offset
1290 ; CHECK: ldp x{{[0-9]+}}, x{{[0-9]+}}, [x{{[0-9]+}}], #-512
1291 ; CHECK: stp x{{[0-9]+}}, x{{[0-9]+}}, [x{{[0-9]+}}], #-512
1294 %phi1 = phi ptr [ %gep4, %for.body ], [ %b, %0 ]
1295 %phi2 = phi ptr [ %gep3, %for.body ], [ %a, %0 ]
1296 %i = phi i64 [ %dec.i, %for.body], [ %count, %0 ]
1297 %gep1 = getelementptr i64, ptr %phi1, i64 1
1298 %load1 = load i64, ptr %gep1
1299 %gep2 = getelementptr i64, ptr %phi2, i64 1
1300 %load2 = load i64, ptr %phi1
1301 store i64 %load1, ptr %gep2
1302 store i64 %load2, ptr %phi2
1303 %dec.i = add nsw i64 %i, -1
1304 %gep3 = getelementptr i64, ptr %phi2, i64 -64
1305 %gep4 = getelementptr i64, ptr %phi1, i64 -64
1306 %cond = icmp sgt i64 %dec.i, 0
1307 br i1 %cond, label %for.body, label %end
1312 define void @post-indexed-paired-offset-out-of-range(ptr %a, ptr %b, i64 %count) nounwind {
1313 ; CHECK-LABEL: post-indexed-paired-offset-out-of-range
1314 ; CHECK: ldp x{{[0-9]+}}, x{{[0-9]+}}, [x{{[0-9]+}}]
1315 ; CHECK: add x{{[0-9]+}}, x{{[0-9]+}}, #512
1316 ; CHECK: stp x{{[0-9]+}}, x{{[0-9]+}}, [x{{[0-9]+}}]
1317 ; CHECK: add x{{[0-9]+}}, x{{[0-9]+}}, #512
1320 %phi1 = phi ptr [ %gep4, %for.body ], [ %b, %0 ]
1321 %phi2 = phi ptr [ %gep3, %for.body ], [ %a, %0 ]
1322 %i = phi i64 [ %dec.i, %for.body], [ %count, %0 ]
1323 %gep1 = getelementptr i64, ptr %phi1, i64 1
1324 %load1 = load i64, ptr %phi1
1325 %gep2 = getelementptr i64, ptr %phi2, i64 1
1326 %load2 = load i64, ptr %gep1
1327 store i64 %load1, ptr %gep2
1328 store i64 %load2, ptr %phi2
1329 %dec.i = add nsw i64 %i, -1
1330 %gep3 = getelementptr i64, ptr %phi2, i64 64
1331 %gep4 = getelementptr i64, ptr %phi1, i64 64
1332 %cond = icmp sgt i64 %dec.i, 0
1333 br i1 %cond, label %for.body, label %end
1338 ; DAGCombiner::MergeConsecutiveStores merges this into a vector store,
1339 ; replaceZeroVectorStore should split the vector store back into
1340 ; scalar stores which should get merged by AArch64LoadStoreOptimizer.
1341 define void @merge_zr32(ptr %p) {
1342 ; CHECK-LABEL: merge_zr32:
1344 ; NOSTRICTALIGN-NEXT: str xzr, [x{{[0-9]+}}]
1345 ; STRICTALIGN-NEXT: stp wzr, wzr, [x{{[0-9]+}}]
1349 %p1 = getelementptr i32, ptr %p, i32 1
1350 store i32 0, ptr %p1
1354 ; Same as merge_zr32 but the merged stores should also get paried.
1355 define void @merge_zr32_2(ptr %p) {
1356 ; CHECK-LABEL: merge_zr32_2:
1358 ; NOSTRICTALIGN-NEXT: stp xzr, xzr, [x{{[0-9]+}}]
1359 ; STRICTALIGN-NEXT: stp wzr, wzr, [x{{[0-9]+}}]
1360 ; STRICTALIGN-NEXT: stp wzr, wzr, [x{{[0-9]+}}, #8]
1364 %p1 = getelementptr i32, ptr %p, i32 1
1365 store i32 0, ptr %p1
1366 %p2 = getelementptr i32, ptr %p, i64 2
1367 store i32 0, ptr %p2
1368 %p3 = getelementptr i32, ptr %p, i64 3
1369 store i32 0, ptr %p3
1373 ; Like merge_zr32_2, but checking the largest allowed stp immediate offset.
1374 define void @merge_zr32_2_offset(ptr %p) {
1375 ; CHECK-LABEL: merge_zr32_2_offset:
1377 ; NOSTRICTALIGN-NEXT: stp xzr, xzr, [x{{[0-9]+}}, #504]
1378 ; STRICTALIGN-NEXT: str wzr, [x{{[0-9]+}}, #504]
1379 ; STRICTALIGN-NEXT: str wzr, [x{{[0-9]+}}, #508]
1380 ; STRICTALIGN-NEXT: str wzr, [x{{[0-9]+}}, #512]
1381 ; STRICTALIGN-NEXT: str wzr, [x{{[0-9]+}}, #516]
1384 %p0 = getelementptr i32, ptr %p, i32 126
1385 store i32 0, ptr %p0
1386 %p1 = getelementptr i32, ptr %p, i32 127
1387 store i32 0, ptr %p1
1388 %p2 = getelementptr i32, ptr %p, i64 128
1389 store i32 0, ptr %p2
1390 %p3 = getelementptr i32, ptr %p, i64 129
1391 store i32 0, ptr %p3
1395 ; Like merge_zr32, but replaceZeroVectorStore should not split this
1396 ; vector store since the address offset is too large for the stp
1398 define void @no_merge_zr32_2_offset(ptr %p) {
1399 ; CHECK-LABEL: no_merge_zr32_2_offset:
1401 ; NOSTRICTALIGN-NEXT: movi v[[REG:[0-9]]].2d, #0000000000000000
1402 ; NOSTRICTALIGN-NEXT: str q[[REG]], [x{{[0-9]+}}, #4096]
1403 ; STRICTALIGN-NEXT: str wzr, [x{{[0-9]+}}, #4096]
1404 ; STRICTALIGN-NEXT: str wzr, [x{{[0-9]+}}, #4100]
1405 ; STRICTALIGN-NEXT: str wzr, [x{{[0-9]+}}, #4104]
1406 ; STRICTALIGN-NEXT: str wzr, [x{{[0-9]+}}, #4108]
1409 %p0 = getelementptr i32, ptr %p, i32 1024
1410 store i32 0, ptr %p0
1411 %p1 = getelementptr i32, ptr %p, i32 1025
1412 store i32 0, ptr %p1
1413 %p2 = getelementptr i32, ptr %p, i64 1026
1414 store i32 0, ptr %p2
1415 %p3 = getelementptr i32, ptr %p, i64 1027
1416 store i32 0, ptr %p3
1420 ; Like merge_zr32, but replaceZeroVectorStore should not split the
1421 ; vector store since the zero constant vector has multiple uses, so we
1422 ; err on the side that allows for stp q instruction generation.
1423 define void @merge_zr32_3(ptr %p) {
1424 ; CHECK-LABEL: merge_zr32_3:
1426 ; NOSTRICTALIGN-NEXT: movi v[[REG:[0-9]]].2d, #0000000000000000
1427 ; NOSTRICTALIGN-NEXT: stp q[[REG]], q[[REG]], [x{{[0-9]+}}]
1428 ; STRICTALIGN-NEXT: stp wzr, wzr, [x{{[0-9]+}}]
1429 ; STRICTALIGN-NEXT: stp wzr, wzr, [x{{[0-9]+}}, #8]
1430 ; STRICTALIGN-NEXT: stp wzr, wzr, [x{{[0-9]+}}, #16]
1431 ; STRICTALIGN-NEXT: stp wzr, wzr, [x{{[0-9]+}}, #24]
1435 %p1 = getelementptr i32, ptr %p, i32 1
1436 store i32 0, ptr %p1
1437 %p2 = getelementptr i32, ptr %p, i64 2
1438 store i32 0, ptr %p2
1439 %p3 = getelementptr i32, ptr %p, i64 3
1440 store i32 0, ptr %p3
1441 %p4 = getelementptr i32, ptr %p, i64 4
1442 store i32 0, ptr %p4
1443 %p5 = getelementptr i32, ptr %p, i64 5
1444 store i32 0, ptr %p5
1445 %p6 = getelementptr i32, ptr %p, i64 6
1446 store i32 0, ptr %p6
1447 %p7 = getelementptr i32, ptr %p, i64 7
1448 store i32 0, ptr %p7
1452 ; Like merge_zr32, but with 2-vector type.
1453 define void @merge_zr32_2vec(ptr %p) {
1454 ; CHECK-LABEL: merge_zr32_2vec:
1456 ; NOSTRICTALIGN-NEXT: str xzr, [x{{[0-9]+}}]
1457 ; STRICTALIGN-NEXT: stp wzr, wzr, [x{{[0-9]+}}]
1460 store <2 x i32> zeroinitializer, ptr %p
1464 ; Like merge_zr32, but with 3-vector type.
1465 define void @merge_zr32_3vec(ptr %p) {
1466 ; CHECK-LABEL: merge_zr32_3vec:
1468 ; NOSTRICTALIGN-NEXT: str wzr, [x{{[0-9]+}}, #8]
1469 ; NOSTRICTALIGN-NEXT: str xzr, [x{{[0-9]+}}]
1470 ; STRICTALIGN-NEXT: stp wzr, wzr, [x{{[0-9]+}}, #4]
1471 ; STRICTALIGN-NEXT: str wzr, [x{{[0-9]+}}]
1474 store <3 x i32> zeroinitializer, ptr %p
1478 ; Like merge_zr32, but with 4-vector type.
1479 define void @merge_zr32_4vec(ptr %p) {
1480 ; CHECK-LABEL: merge_zr32_4vec:
1482 ; NOSTRICTALIGN-NEXT: stp xzr, xzr, [x{{[0-9]+}}]
1483 ; STRICTALIGN-NEXT: stp wzr, wzr, [x{{[0-9]+}}, #8]
1484 ; STRICTALIGN-NEXT: stp wzr, wzr, [x{{[0-9]+}}]
1487 store <4 x i32> zeroinitializer, ptr %p
1491 ; Like merge_zr32, but with 2-vector float type.
1492 define void @merge_zr32_2vecf(ptr %p) {
1493 ; CHECK-LABEL: merge_zr32_2vecf:
1495 ; NOSTRICTALIGN-NEXT: str xzr, [x{{[0-9]+}}]
1496 ; STRICTALIGN-NEXT: stp wzr, wzr, [x{{[0-9]+}}]
1499 store <2 x float> zeroinitializer, ptr %p
1503 ; Like merge_zr32, but with 4-vector float type.
1504 define void @merge_zr32_4vecf(ptr %p) {
1505 ; CHECK-LABEL: merge_zr32_4vecf:
1507 ; NOSTRICTALIGN-NEXT: stp xzr, xzr, [x{{[0-9]+}}]
1508 ; STRICTALIGN-NEXT: stp wzr, wzr, [x{{[0-9]+}}, #8]
1509 ; STRICTALIGN-NEXT: stp wzr, wzr, [x{{[0-9]+}}]
1512 store <4 x float> zeroinitializer, ptr %p
1516 ; Similar to merge_zr32, but for 64-bit values.
1517 define void @merge_zr64(ptr %p) {
1518 ; CHECK-LABEL: merge_zr64:
1520 ; CHECK-NEXT: stp xzr, xzr, [x{{[0-9]+}}]
1524 %p1 = getelementptr i64, ptr %p, i64 1
1525 store i64 0, ptr %p1
1529 ; Similar to merge_zr32, but for 64-bit values and with unaligned stores.
1530 define void @merge_zr64_unalign(ptr %p) {
1531 ; CHECK-LABEL: merge_zr64_unalign:
1533 ; NOSTRICTALIGN-NEXT: stp xzr, xzr, [x{{[0-9]+}}]
1552 store <2 x i64> zeroinitializer, ptr %p, align 1
1556 ; Similar to merge_zr32_3, replaceZeroVectorStore should not split the
1557 ; vector store since the zero constant vector has multiple uses.
1558 define void @merge_zr64_2(ptr %p) {
1559 ; CHECK-LABEL: merge_zr64_2:
1561 ; NOSTRICTALIGN-NEXT: movi v[[REG:[0-9]]].2d, #0000000000000000
1562 ; NOSTRICTALIGN-NEXT: stp q[[REG]], q[[REG]], [x{{[0-9]+}}]
1563 ; STRICTALIGN-NEXT: stp xzr, xzr, [x{{[0-9]+}}]
1564 ; STRICTALIGN-NEXT: stp xzr, xzr, [x{{[0-9]+}}, #16]
1568 %p1 = getelementptr i64, ptr %p, i64 1
1569 store i64 0, ptr %p1
1570 %p2 = getelementptr i64, ptr %p, i64 2
1571 store i64 0, ptr %p2
1572 %p3 = getelementptr i64, ptr %p, i64 3
1573 store i64 0, ptr %p3
1577 ; Like merge_zr64, but with 2-vector double type.
1578 define void @merge_zr64_2vecd(ptr %p) {
1579 ; CHECK-LABEL: merge_zr64_2vecd:
1581 ; CHECK-NEXT: stp xzr, xzr, [x{{[0-9]+}}]
1584 store <2 x double> zeroinitializer, ptr %p
1588 ; Like merge_zr64, but with 3-vector i64 type.
1589 define void @merge_zr64_3vec(ptr %p) {
1590 ; CHECK-LABEL: merge_zr64_3vec:
1592 ; CHECK-NEXT: stp xzr, xzr, [x{{[0-9]+}}, #8]
1593 ; CHECK-NEXT: str xzr, [x{{[0-9]+}}]
1596 store <3 x i64> zeroinitializer, ptr %p
1600 ; Like merge_zr64_2, but with 4-vector double type.
1601 define void @merge_zr64_4vecd(ptr %p) {
1602 ; CHECK-LABEL: merge_zr64_4vecd:
1604 ; CHECK-NEXT: movi v[[REG:[0-9]]].2d, #0000000000000000
1605 ; CHECK-NEXT: stp q[[REG]], q[[REG]], [x{{[0-9]+}}]
1608 store <4 x double> zeroinitializer, ptr %p
1612 ; Verify that non-consecutive merges do not generate q0
1613 define void @merge_multiple_128bit_stores(ptr %p) {
1614 ; CHECK-LABEL: merge_multiple_128bit_stores
1616 ; NOSTRICTALIGN-NEXT: movi v[[REG:[0-9]]].2d, #0000000000000000
1617 ; NOSTRICTALIGN-NEXT: str q0, [x0]
1618 ; NOSTRICTALIGN-NEXT: stur q0, [x0, #24]
1619 ; NOSTRICTALIGN-NEXT: str q0, [x0, #48]
1620 ; STRICTALIGN-NEXT: stp xzr, xzr, [x0]
1621 ; STRICTALIGN-NEXT: stp xzr, xzr, [x0, #24]
1622 ; STRICTALIGN-NEXT: stp xzr, xzr, [x0, #48]
1626 %p1 = getelementptr i64, ptr %p, i64 1
1627 store i64 0, ptr %p1
1628 %p3 = getelementptr i64, ptr %p, i64 3
1629 store i64 0, ptr %p3
1630 %p4 = getelementptr i64, ptr %p, i64 4
1631 store i64 0, ptr %p4
1632 %p6 = getelementptr i64, ptr %p, i64 6
1633 store i64 0, ptr %p6
1634 %p7 = getelementptr i64, ptr %p, i64 7
1635 store i64 0, ptr %p7
1639 ; Verify that large stores generate stp q
1640 define void @merge_multiple_128bit_stores_consec(ptr %p) {
1641 ; CHECK-LABEL: merge_multiple_128bit_stores_consec
1643 ; NOSTRICTALIGN-NEXT: movi v[[REG:[0-9]]].2d, #0000000000000000
1644 ; NOSTRICTALIGN-NEXT: stp q[[REG]], q[[REG]], [x{{[0-9]+}}]
1645 ; NOSTRICTALIGN-NEXT: stp q[[REG]], q[[REG]], [x{{[0-9]+}}, #32]
1646 ; STRICTALIGN-NEXT: stp xzr, xzr, [x0]
1647 ; STRICTALIGN-NEXT: stp xzr, xzr, [x0, #16]
1648 ; STRICTALIGN-NEXT: stp xzr, xzr, [x0, #32]
1649 ; STRICTALIGN-NEXT: stp xzr, xzr, [x0, #48]
1653 %p1 = getelementptr i64, ptr %p, i64 1
1654 store i64 0, ptr %p1
1655 %p2 = getelementptr i64, ptr %p, i64 2
1656 store i64 0, ptr %p2
1657 %p3 = getelementptr i64, ptr %p, i64 3
1658 store i64 0, ptr %p3
1659 %p4 = getelementptr i64, ptr %p, i64 4
1660 store i64 0, ptr %p4
1661 %p5 = getelementptr i64, ptr %p, i64 5
1662 store i64 0, ptr %p5
1663 %p6 = getelementptr i64, ptr %p, i64 6
1664 store i64 0, ptr %p6
1665 %p7 = getelementptr i64, ptr %p, i64 7
1666 store i64 0, ptr %p7
1670 ; Check for bug 34674 where invalid add of xzr was being generated.
1671 ; CHECK-LABEL: bug34674:
1673 ; CHECK-NEXT: mov [[ZREG:x[0-9]+]], xzr
1674 ; CHECK-NEXT: mov x8, x0
1675 ; CHECK-NEXT: add x0, [[ZREG]], #1
1676 ; CHECK-NEXT: stp xzr, xzr, [x8]
1677 define i64 @bug34674(ptr %p) {
1679 store <2 x i64> zeroinitializer, ptr %p
1680 %ld = load i64, ptr %p
1681 %add = add i64 %ld, 1
1685 ; CHECK-LABEL: trunc_splat_zero:
1686 ; CHECK-DAG: strh wzr, [x0]
1687 define void @trunc_splat_zero(ptr %ptr) {
1688 store <2 x i8> zeroinitializer, ptr %ptr, align 2
1692 ; CHECK-LABEL: trunc_splat:
1693 ; CHECK: mov [[VAL:w[0-9]+]], #42
1694 ; CHECK: movk [[VAL]], #42, lsl #16
1695 ; CHECK: str [[VAL]], [x0]
1696 define void @trunc_splat(ptr %ptr) {
1697 store <2 x i16> <i16 42, i16 42>, ptr %ptr, align 4