[NFC][RemoveDIs] Prefer iterators over inst-pointers in InstCombine
[llvm-project.git] / llvm / test / CodeGen / AArch64 / GlobalISel / merge-stores-truncating.ll
blob7fd71b26fa1ba7a4e01fecc4b0506838efcdaf85
1 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2 ; RUN: llc < %s -mtriple=aarch64-apple-ios -global-isel -global-isel-abort=1 | FileCheck %s
4 define dso_local void @trunc_i16_to_i8(i16 %x, ptr %p) {
5 ; CHECK-LABEL: trunc_i16_to_i8:
6 ; CHECK:       ; %bb.0:
7 ; CHECK-NEXT:    strh w0, [x1]
8 ; CHECK-NEXT:    ret
9   %t1 = trunc i16 %x to i8
10   %sh = lshr i16 %x, 8
11   %t2 = trunc i16 %sh to i8
12   store i8 %t1, ptr %p, align 1
13   %p1 = getelementptr inbounds i8, ptr %p, i64 1
14   store i8 %t2, ptr %p1, align 1
15   ret void
18 define dso_local void @trunc_i32_to_i8(i32 %x, ptr %p) {
19 ; CHECK-LABEL: trunc_i32_to_i8:
20 ; CHECK:       ; %bb.0:
21 ; CHECK-NEXT:    str w0, [x1]
22 ; CHECK-NEXT:    ret
23   %t1 = trunc i32 %x to i8
24   %sh1 = lshr i32 %x, 8
25   %t2 = trunc i32 %sh1 to i8
26   %sh2 = lshr i32 %x, 16
27   %t3 = trunc i32 %sh2 to i8
28   %sh3 = lshr i32 %x, 24
29   %t4 = trunc i32 %sh3 to i8
30   store i8 %t1, ptr %p, align 1
31   %p1 = getelementptr inbounds i8, ptr %p, i64 1
32   store i8 %t2, ptr %p1, align 1
33   %p2 = getelementptr inbounds i8, ptr %p, i64 2
34   store i8 %t3, ptr %p2, align 1
35   %p3 = getelementptr inbounds i8, ptr %p, i64 3
36   store i8 %t4, ptr %p3, align 1
37   ret void
40 define dso_local void @trunc_i32_to_i16(i32 %x, ptr %p) {
41 ; CHECK-LABEL: trunc_i32_to_i16:
42 ; CHECK:       ; %bb.0:
43 ; CHECK-NEXT:    str w0, [x1]
44 ; CHECK-NEXT:    ret
45   %t1 = trunc i32 %x to i16
46   %sh = lshr i32 %x, 16
47   %t2 = trunc i32 %sh to i16
48   store i16 %t1, ptr %p, align 2
49   %p1 = getelementptr inbounds i16, ptr %p, i64 1
50   store i16 %t2, ptr %p1, align 2
51   ret void
54 define dso_local void @be_i32_to_i16(i32 %x, ptr %p0) {
55 ; CHECK-LABEL: be_i32_to_i16:
56 ; CHECK:       ; %bb.0:
57 ; CHECK-NEXT:    ror w8, w0, #16
58 ; CHECK-NEXT:    str w8, [x1]
59 ; CHECK-NEXT:    ret
60   %sh1 = lshr i32 %x, 16
61   %t0 = trunc i32 %x to i16
62   %t1 = trunc i32 %sh1 to i16
63   %p1 = getelementptr inbounds i16, ptr %p0, i64 1
64   store i16 %t0, ptr %p1, align 2
65   store i16 %t1, ptr %p0, align 2
66   ret void
69 define dso_local void @be_i32_to_i16_order(i32 %x, ptr %p0) {
70 ; CHECK-LABEL: be_i32_to_i16_order:
71 ; CHECK:       ; %bb.0:
72 ; CHECK-NEXT:    ror w8, w0, #16
73 ; CHECK-NEXT:    str w8, [x1]
74 ; CHECK-NEXT:    ret
75   %sh1 = lshr i32 %x, 16
76   %t0 = trunc i32 %x to i16
77   %t1 = trunc i32 %sh1 to i16
78   %p1 = getelementptr inbounds i16, ptr %p0, i64 1
79   store i16 %t1, ptr %p0, align 2
80   store i16 %t0, ptr %p1, align 2
81   ret void
84 define dso_local void @trunc_i64_to_i8(i64 %x, ptr %p) {
85 ; CHECK-LABEL: trunc_i64_to_i8:
86 ; CHECK:       ; %bb.0:
87 ; CHECK-NEXT:    str x0, [x1]
88 ; CHECK-NEXT:    ret
89   %t1 = trunc i64 %x to i8
90   %sh1 = lshr i64 %x, 8
91   %t2 = trunc i64 %sh1 to i8
92   %sh2 = lshr i64 %x, 16
93   %t3 = trunc i64 %sh2 to i8
94   %sh3 = lshr i64 %x, 24
95   %t4 = trunc i64 %sh3 to i8
96   %sh4 = lshr i64 %x, 32
97   %t5 = trunc i64 %sh4 to i8
98   %sh5 = lshr i64 %x, 40
99   %t6 = trunc i64 %sh5 to i8
100   %sh6 = lshr i64 %x, 48
101   %t7 = trunc i64 %sh6 to i8
102   %sh7 = lshr i64 %x, 56
103   %t8 = trunc i64 %sh7 to i8
104   store i8 %t1, ptr %p, align 1
105   %p1 = getelementptr inbounds i8, ptr %p, i64 1
106   store i8 %t2, ptr %p1, align 1
107   %p2 = getelementptr inbounds i8, ptr %p, i64 2
108   store i8 %t3, ptr %p2, align 1
109   %p3 = getelementptr inbounds i8, ptr %p, i64 3
110   store i8 %t4, ptr %p3, align 1
111   %p4 = getelementptr inbounds i8, ptr %p, i64 4
112   store i8 %t5, ptr %p4, align 1
113   %p5 = getelementptr inbounds i8, ptr %p, i64 5
114   store i8 %t6, ptr %p5, align 1
115   %p6 = getelementptr inbounds i8, ptr %p, i64 6
116   store i8 %t7, ptr %p6, align 1
117   %p7 = getelementptr inbounds i8, ptr %p, i64 7
118   store i8 %t8, ptr %p7, align 1
119   ret void
122 define dso_local void @trunc_i64_to_i16(i64 %x, ptr %p) {
123 ; CHECK-LABEL: trunc_i64_to_i16:
124 ; CHECK:       ; %bb.0:
125 ; CHECK-NEXT:    str x0, [x1]
126 ; CHECK-NEXT:    ret
127   %t1 = trunc i64 %x to i16
128   %sh1 = lshr i64 %x, 16
129   %t2 = trunc i64 %sh1 to i16
130   %sh2 = lshr i64 %x, 32
131   %t3 = trunc i64 %sh2 to i16
132   %sh3 = lshr i64 %x, 48
133   %t4 = trunc i64 %sh3 to i16
134   store i16 %t1, ptr %p, align 2
135   %p1 = getelementptr inbounds i16, ptr %p, i64 1
136   store i16 %t2, ptr %p1, align 2
137   %p2 = getelementptr inbounds i16, ptr %p, i64 2
138   store i16 %t3, ptr %p2, align 2
139   %p3 = getelementptr inbounds i16, ptr %p, i64 3
140   store i16 %t4, ptr %p3, align 2
141   ret void
144 define dso_local void @trunc_i64_to_i32(i64 %x, ptr %p) {
145 ; CHECK-LABEL: trunc_i64_to_i32:
146 ; CHECK:       ; %bb.0:
147 ; CHECK-NEXT:    str x0, [x1]
148 ; CHECK-NEXT:    ret
149   %t1 = trunc i64 %x to i32
150   %sh = lshr i64 %x, 32
151   %t2 = trunc i64 %sh to i32
152   store i32 %t1, ptr %p, align 4
153   %p1 = getelementptr inbounds i32, ptr %p, i64 1
154   store i32 %t2, ptr %p1, align 4
155   ret void
157 define dso_local void @be_i64_to_i32(i64 %x, ptr %p0) {
158 ; CHECK-LABEL: be_i64_to_i32:
159 ; CHECK:       ; %bb.0:
160 ; CHECK-NEXT:    ror x8, x0, #32
161 ; CHECK-NEXT:    str x8, [x1]
162 ; CHECK-NEXT:    ret
163   %sh1 = lshr i64 %x, 32
164   %t0 = trunc i64 %x to i32
165   %t1 = trunc i64 %sh1 to i32
166   %p1 = getelementptr inbounds i32, ptr %p0, i64 1
167   store i32 %t0, ptr %p1, align 4
168   store i32 %t1, ptr %p0, align 4
169   ret void
172 define dso_local void @be_i64_to_i32_order(i64 %x, ptr %p0) {
173 ; CHECK-LABEL: be_i64_to_i32_order:
174 ; CHECK:       ; %bb.0:
175 ; CHECK-NEXT:    ror x8, x0, #32
176 ; CHECK-NEXT:    str x8, [x1]
177 ; CHECK-NEXT:    ret
178   %sh1 = lshr i64 %x, 32
179   %t0 = trunc i64 %x to i32
180   %t1 = trunc i64 %sh1 to i32
181   %p1 = getelementptr inbounds i32, ptr %p0, i64 1
182   store i32 %t1, ptr %p0, align 4
183   store i32 %t0, ptr %p1, align 4
184   ret void
187 ; Negative tests.
189 define void @merge_hole(i32 %x, ptr %p) {
190 ; CHECK-LABEL: merge_hole:
191 ; CHECK:       ; %bb.0:
192 ; CHECK-NEXT:    lsr w8, w0, #16
193 ; CHECK-NEXT:    strb w0, [x1]
194 ; CHECK-NEXT:    strh w8, [x1, #2]
195 ; CHECK-NEXT:    ret
196   %p2 = getelementptr inbounds i16, ptr %p, i64 1
197   %x3 = trunc i32 %x to i8
198   store i8 %x3, ptr %p, align 1
199   %sh = lshr i32 %x, 16
200   %x01 = trunc i32 %sh to i16
201   store i16 %x01, ptr %p2, align 1
202   ret void
205 define void @merge_hole2(i32 %x, ptr %p) {
206 ; CHECK-LABEL: merge_hole2:
207 ; CHECK:       ; %bb.0:
208 ; CHECK-NEXT:    lsr w8, w0, #16
209 ; CHECK-NEXT:    strb w0, [x1]
210 ; CHECK-NEXT:    strh w8, [x1, #2]
211 ; CHECK-NEXT:    ret
212   %p2 = getelementptr inbounds i16, ptr %p, i64 1
213   %sh = lshr i32 %x, 16
214   %x01 = trunc i32 %sh to i16
215   store i16 %x01, ptr %p2, align 1
216   %x3 = trunc i32 %x to i8
217   store i8 %x3, ptr %p, align 1
218   ret void
221 define void @merge_hole3(i32 %x, ptr %p) {
222 ; CHECK-LABEL: merge_hole3:
223 ; CHECK:       ; %bb.0:
224 ; CHECK-NEXT:    lsr w8, w0, #16
225 ; CHECK-NEXT:    strb w0, [x1, #1]
226 ; CHECK-NEXT:    strh w8, [x1, #2]
227 ; CHECK-NEXT:    ret
228   %p1 = getelementptr inbounds i8, ptr %p, i64 1
229   %p2 = getelementptr inbounds i16, ptr %p, i64 1
230   %x3 = trunc i32 %x to i8
231   store i8 %x3, ptr %p1, align 1
232   %sh = lshr i32 %x, 16
233   %x01 = trunc i32 %sh to i16
234   store i16 %x01, ptr %p2, align 1
235   ret void
238 define void @merge_hole4(i32 %x, ptr %p) {
239 ; CHECK-LABEL: merge_hole4:
240 ; CHECK:       ; %bb.0:
241 ; CHECK-NEXT:    lsr w8, w0, #16
242 ; CHECK-NEXT:    strb w0, [x1, #2]
243 ; CHECK-NEXT:    strh w8, [x1]
244 ; CHECK-NEXT:    ret
245   %p2 = getelementptr inbounds i8, ptr %p, i64 2
246   %x3 = trunc i32 %x to i8
247   store i8 %x3, ptr %p2, align 1
248   %sh = lshr i32 %x, 16
249   %x01 = trunc i32 %sh to i16
250   store i16 %x01, ptr %p, align 1
251   ret void
254 define dso_local i32 @load_between_stores(i32 %x, ptr %p, ptr %ptr) {
255 ; CHECK-LABEL: load_between_stores:
256 ; CHECK:       ; %bb.0:
257 ; CHECK-NEXT:    strh w0, [x1]
258 ; CHECK-NEXT:    lsr w9, w0, #16
259 ; CHECK-NEXT:    ldr w8, [x2]
260 ; CHECK-NEXT:    strh w9, [x1, #2]
261 ; CHECK-NEXT:    mov w0, w8
262 ; CHECK-NEXT:    ret
263   %t1 = trunc i32 %x to i16
264   %sh = lshr i32 %x, 16
265   %t2 = trunc i32 %sh to i16
266   store i16 %t1, ptr %p, align 2
267   %ld = load i32, ptr %ptr
268   %p1 = getelementptr inbounds i16, ptr %p, i64 1
269   store i16 %t2, ptr %p1, align 2
270   ret i32 %ld
273 define dso_local void @invalid_shift(i16 %x, ptr %p) {
274 ; CHECK-LABEL: invalid_shift:
275 ; CHECK:       ; %bb.0:
276 ; CHECK-NEXT:    ubfx w8, w0, #4, #12
277 ; CHECK-NEXT:    strb w0, [x1]
278 ; CHECK-NEXT:    strb w8, [x1, #1]
279 ; CHECK-NEXT:    ret
280   %t1 = trunc i16 %x to i8
281   %sh = lshr i16 %x, 4
282   %t2 = trunc i16 %sh to i8
283   store i8 %t1, ptr %p, align 1
284   %p1 = getelementptr inbounds i8, ptr %p, i64 1
285   store i8 %t2, ptr %p1, align 1
286   ret void
289 define dso_local void @missing_store(i32 %x, ptr %p) {
290 ; The missing store of shift 16 means we can't merge to 32 bit store,
291 ; but we can still partially merge to a 16 bit one.
292 ; CHECK-LABEL: missing_store:
293 ; CHECK:       ; %bb.0:
294 ; CHECK-NEXT:    lsr w8, w0, #24
295 ; CHECK-NEXT:    strh w0, [x1]
296 ; CHECK-NEXT:    strb w8, [x1, #3]
297 ; CHECK-NEXT:    ret
298   %t1 = trunc i32 %x to i8
299   %sh1 = lshr i32 %x, 8
300   %t2 = trunc i32 %sh1 to i8
301   %sh3 = lshr i32 %x, 24
302   %t4 = trunc i32 %sh3 to i8
303   store i8 %t1, ptr %p, align 1
304   %p1 = getelementptr inbounds i8, ptr %p, i64 1
305   store i8 %t2, ptr %p1, align 1
306   %p3 = getelementptr inbounds i8, ptr %p, i64 3
307   store i8 %t4, ptr %p3, align 1
308   ret void
311 define dso_local void @different_base_reg(i16 %x, ptr %p, ptr %p2) {
312 ; CHECK-LABEL: different_base_reg:
313 ; CHECK:       ; %bb.0:
314 ; CHECK-NEXT:    ubfx w8, w0, #8, #8
315 ; CHECK-NEXT:    strb w0, [x1]
316 ; CHECK-NEXT:    strb w8, [x2, #1]
317 ; CHECK-NEXT:    ret
318   %t1 = trunc i16 %x to i8
319   %sh = lshr i16 %x, 8
320   %t2 = trunc i16 %sh to i8
321   store i8 %t1, ptr %p, align 1
322   %p1 = getelementptr inbounds i8, ptr %p2, i64 1
323   store i8 %t2, ptr %p1, align 1
324   ret void
327 define dso_local void @second_store_is_volatile(i16 %x, ptr %p) {
328 ; CHECK-LABEL: second_store_is_volatile:
329 ; CHECK:       ; %bb.0:
330 ; CHECK-NEXT:    ubfx w8, w0, #8, #8
331 ; CHECK-NEXT:    strb w0, [x1]
332 ; CHECK-NEXT:    strb w8, [x1, #1]
333 ; CHECK-NEXT:    ret
334   %t1 = trunc i16 %x to i8
335   %sh = lshr i16 %x, 8
336   %t2 = trunc i16 %sh to i8
337   store volatile i8 %t1, ptr %p, align 1
338   %p1 = getelementptr inbounds i8, ptr %p, i64 1
339   store i8 %t2, ptr %p1, align 1
340   ret void
343 declare void @use_ptr(ptr)
345 define dso_local void @trunc_from_larger_src_val(i64 %hold.4.lcssa, ptr %check1792) {
346   ; Here we can merge these i8 stores into a single i32 store, but first we need
347   ; to truncate the i64 value to i32.
348 ; CHECK-LABEL: trunc_from_larger_src_val:
349 ; CHECK:       ; %bb.0:
350 ; CHECK-NEXT:    sub sp, sp, #32
351 ; CHECK-NEXT:    stp x29, x30, [sp, #16] ; 16-byte Folded Spill
352 ; CHECK-NEXT:    .cfi_def_cfa_offset 32
353 ; CHECK-NEXT:    .cfi_offset w30, -8
354 ; CHECK-NEXT:    .cfi_offset w29, -16
355 ; CHECK-NEXT:    str w0, [sp, #12]
356 ; CHECK-NEXT:    add x0, sp, #12
357 ; CHECK-NEXT:    bl _use_ptr
358 ; CHECK-NEXT:    ldp x29, x30, [sp, #16] ; 16-byte Folded Reload
359 ; CHECK-NEXT:    add sp, sp, #32
360 ; CHECK-NEXT:    ret
361   %hbuf = alloca [4 x i8], align 1
362   %arrayidx177 = getelementptr inbounds [4 x i8], ptr %hbuf, i64 0, i64 1
363   %arrayidx234 = getelementptr inbounds [4 x i8], ptr %hbuf, i64 0, i64 2
364   %arrayidx237 = getelementptr inbounds [4 x i8], ptr %hbuf, i64 0, i64 3
365   %conv227 = trunc i64 %hold.4.lcssa to i8
366   store i8 %conv227, ptr %hbuf, align 1
367   %shr229 = lshr i64 %hold.4.lcssa, 8
368   %conv230 = trunc i64 %shr229 to i8
369   store i8 %conv230, ptr %arrayidx177, align 1
370   %shr232 = lshr i64 %hold.4.lcssa, 16
371   %conv233 = trunc i64 %shr232 to i8
372   store i8 %conv233, ptr %arrayidx234, align 1
373   %shr235 = lshr i64 %hold.4.lcssa, 24
374   %conv236 = trunc i64 %shr235 to i8
375   store i8 %conv236, ptr %arrayidx237, align 1
376   call void @use_ptr(ptr noundef nonnull %hbuf)
377   ret void