[ARM] More MVE compare vector splat combines for ANDs
[llvm-complete.git] / test / CodeGen / AArch64 / arm64-fold-lsl.ll
blob0790e4c58c4676bb4376b0a8dab35362facb081a
1 ; RUN: llc < %s -mtriple=arm64-eabi -aarch64-neon-syntax=apple | FileCheck %s
3 ; <rdar://problem/14486451>
5 %struct.a = type [256 x i16]
6 %struct.b = type [256 x i32]
7 %struct.c = type [256 x i64]
9 define i16 @load_halfword(%struct.a* %ctx, i32 %xor72) nounwind {
10 ; CHECK-LABEL: load_halfword:
11 ; CHECK: ubfx [[REG:x[0-9]+]], x1, #9, #8
12 ; CHECK: ldrh w0, [x0, [[REG]], lsl #1]
13   %shr81 = lshr i32 %xor72, 9
14   %conv82 = zext i32 %shr81 to i64
15   %idxprom83 = and i64 %conv82, 255
16   %arrayidx86 = getelementptr inbounds %struct.a, %struct.a* %ctx, i64 0, i64 %idxprom83
17   %result = load i16, i16* %arrayidx86, align 2
18   ret i16 %result
21 define i32 @load_word(%struct.b* %ctx, i32 %xor72) nounwind {
22 ; CHECK-LABEL: load_word:
23 ; CHECK: ubfx [[REG:x[0-9]+]], x1, #9, #8
24 ; CHECK: ldr w0, [x0, [[REG]], lsl #2]
25   %shr81 = lshr i32 %xor72, 9
26   %conv82 = zext i32 %shr81 to i64
27   %idxprom83 = and i64 %conv82, 255
28   %arrayidx86 = getelementptr inbounds %struct.b, %struct.b* %ctx, i64 0, i64 %idxprom83
29   %result = load i32, i32* %arrayidx86, align 4
30   ret i32 %result
33 define i64 @load_doubleword(%struct.c* %ctx, i32 %xor72) nounwind {
34 ; CHECK-LABEL: load_doubleword:
35 ; CHECK: ubfx [[REG:x[0-9]+]], x1, #9, #8
36 ; CHECK: ldr x0, [x0, [[REG]], lsl #3]
37   %shr81 = lshr i32 %xor72, 9
38   %conv82 = zext i32 %shr81 to i64
39   %idxprom83 = and i64 %conv82, 255
40   %arrayidx86 = getelementptr inbounds %struct.c, %struct.c* %ctx, i64 0, i64 %idxprom83
41   %result = load i64, i64* %arrayidx86, align 8
42   ret i64 %result
45 define void @store_halfword(%struct.a* %ctx, i32 %xor72, i16 %val) nounwind {
46 ; CHECK-LABEL: store_halfword:
47 ; CHECK: ubfx [[REG:x[0-9]+]], x1, #9, #8
48 ; CHECK: strh w2, [x0, [[REG]], lsl #1]
49   %shr81 = lshr i32 %xor72, 9
50   %conv82 = zext i32 %shr81 to i64
51   %idxprom83 = and i64 %conv82, 255
52   %arrayidx86 = getelementptr inbounds %struct.a, %struct.a* %ctx, i64 0, i64 %idxprom83
53   store i16 %val, i16* %arrayidx86, align 8
54   ret void
57 define void @store_word(%struct.b* %ctx, i32 %xor72, i32 %val) nounwind {
58 ; CHECK-LABEL: store_word:
59 ; CHECK: ubfx [[REG:x[0-9]+]], x1, #9, #8
60 ; CHECK: str w2, [x0, [[REG]], lsl #2]
61   %shr81 = lshr i32 %xor72, 9
62   %conv82 = zext i32 %shr81 to i64
63   %idxprom83 = and i64 %conv82, 255
64   %arrayidx86 = getelementptr inbounds %struct.b, %struct.b* %ctx, i64 0, i64 %idxprom83
65   store i32 %val, i32* %arrayidx86, align 8
66   ret void
69 define void @store_doubleword(%struct.c* %ctx, i32 %xor72, i64 %val) nounwind {
70 ; CHECK-LABEL: store_doubleword:
71 ; CHECK: ubfx [[REG:x[0-9]+]], x1, #9, #8
72 ; CHECK: str x2, [x0, [[REG]], lsl #3]
73   %shr81 = lshr i32 %xor72, 9
74   %conv82 = zext i32 %shr81 to i64
75   %idxprom83 = and i64 %conv82, 255
76   %arrayidx86 = getelementptr inbounds %struct.c, %struct.c* %ctx, i64 0, i64 %idxprom83
77   store i64 %val, i64* %arrayidx86, align 8
78   ret void
81 ; Check that we combine a shift into the offset instead of using a narrower load
82 ; when we have a load followed by a trunc
84 define i32 @load_doubleword_trunc_word(i64* %ptr, i64 %off) {
85 ; CHECK-LABEL: load_doubleword_trunc_word:
86 ; CHECK: ldr x0, [x0, x1, lsl #3]
87 entry:
88   %idx = getelementptr inbounds i64, i64* %ptr, i64 %off
89   %x = load i64, i64* %idx, align 8
90   %trunc = trunc i64 %x to i32
91   ret i32 %trunc
94 define i16 @load_doubleword_trunc_halfword(i64* %ptr, i64 %off) {
95 ; CHECK-LABEL: load_doubleword_trunc_halfword:
96 ; CHECK: ldr x0, [x0, x1, lsl #3]
97 entry:
98   %idx = getelementptr inbounds i64, i64* %ptr, i64 %off
99   %x = load i64, i64* %idx, align 8
100   %trunc = trunc i64 %x to i16
101   ret i16 %trunc
104 define i8 @load_doubleword_trunc_byte(i64* %ptr, i64 %off) {
105 ; CHECK-LABEL: load_doubleword_trunc_byte:
106 ; CHECK: ldr x0, [x0, x1, lsl #3]
107 entry:
108   %idx = getelementptr inbounds i64, i64* %ptr, i64 %off
109   %x = load i64, i64* %idx, align 8
110   %trunc = trunc i64 %x to i8
111   ret i8 %trunc
114 define i16 @load_word_trunc_halfword(i32* %ptr, i64 %off) {
115 entry:
116 ; CHECK-LABEL: load_word_trunc_halfword:
117 ; CHECK: ldr w0, [x0, x1, lsl #2]
118   %idx = getelementptr inbounds i32, i32* %ptr, i64 %off
119   %x = load i32, i32* %idx, align 8
120   %trunc = trunc i32 %x to i16
121   ret i16 %trunc
124 define i8 @load_word_trunc_byte(i32* %ptr, i64 %off) {
125 ; CHECK-LABEL: load_word_trunc_byte:
126 ; CHECK: ldr w0, [x0, x1, lsl #2]
127 entry:
128  %idx = getelementptr inbounds i32, i32* %ptr, i64 %off
129  %x = load i32, i32* %idx, align 8
130  %trunc = trunc i32 %x to i8
131  ret i8 %trunc
134 define i8 @load_halfword_trunc_byte(i16* %ptr, i64 %off) {
135 ; CHECK-LABEL: load_halfword_trunc_byte:
136 ; CHECK: ldrh w0, [x0, x1, lsl #1]
137 entry:
138  %idx = getelementptr inbounds i16, i16* %ptr, i64 %off
139  %x = load i16, i16* %idx, align 8
140  %trunc = trunc i16 %x to i8
141  ret i8 %trunc
144 ; Check that we do use a narrower load, and so don't combine the shift, when
145 ; the loaded value is zero-extended.
147 define i64 @load_doubleword_trunc_word_zext(i64* %ptr, i64 %off) {
148 ; CHECK-LABEL: load_doubleword_trunc_word_zext:
149 ; CHECK: lsl [[REG:x[0-9]+]], x1, #3
150 ; CHECK: ldr w0, [x0, [[REG]]]
151 entry:
152   %idx = getelementptr inbounds i64, i64* %ptr, i64 %off
153   %x = load i64, i64* %idx, align 8
154   %trunc = trunc i64 %x to i32
155   %ext = zext i32 %trunc to i64
156   ret i64 %ext
159 define i64 @load_doubleword_trunc_halfword_zext(i64* %ptr, i64 %off) {
160 ; CHECK-LABEL: load_doubleword_trunc_halfword_zext:
161 ; CHECK: lsl [[REG:x[0-9]+]], x1, #3
162 ; CHECK: ldrh w0, [x0, [[REG]]]
163 entry:
164   %idx = getelementptr inbounds i64, i64* %ptr, i64 %off
165   %x = load i64, i64* %idx, align 8
166   %trunc = trunc i64 %x to i16
167   %ext = zext i16 %trunc to i64
168   ret i64 %ext
171 define i64 @load_doubleword_trunc_byte_zext(i64* %ptr, i64 %off) {
172 ; CHECK-LABEL: load_doubleword_trunc_byte_zext:
173 ; CHECK: lsl [[REG:x[0-9]+]], x1, #3
174 ; CHECK: ldrb w0, [x0, [[REG]]]
175 entry:
176   %idx = getelementptr inbounds i64, i64* %ptr, i64 %off
177   %x = load i64, i64* %idx, align 8
178   %trunc = trunc i64 %x to i8
179   %ext = zext i8 %trunc to i64
180   ret i64 %ext
183 define i64 @load_word_trunc_halfword_zext(i32* %ptr, i64 %off) {
184 ; CHECK-LABEL: load_word_trunc_halfword_zext:
185 ; CHECK: lsl [[REG:x[0-9]+]], x1, #2
186 ; CHECK: ldrh w0, [x0, [[REG]]]
187 entry:
188   %idx = getelementptr inbounds i32, i32* %ptr, i64 %off
189   %x = load i32, i32* %idx, align 8
190   %trunc = trunc i32 %x to i16
191   %ext = zext i16 %trunc to i64
192   ret i64 %ext
195 define i64 @load_word_trunc_byte_zext(i32* %ptr, i64 %off) {
196 ; CHECK-LABEL: load_word_trunc_byte_zext:
197 ; CHECK: lsl [[REG:x[0-9]+]], x1, #2
198 ; CHECK: ldrb w0, [x0, [[REG]]]
199 entry:
200  %idx = getelementptr inbounds i32, i32* %ptr, i64 %off
201  %x = load i32, i32* %idx, align 8
202  %trunc = trunc i32 %x to i8
203  %ext = zext i8 %trunc to i64
204  ret i64 %ext
207 define i64 @load_halfword_trunc_byte_zext(i16* %ptr, i64 %off) {
208 ; CHECK-LABEL: load_halfword_trunc_byte_zext:
209 ; CHECK: lsl [[REG:x[0-9]+]], x1, #1
210 ; CHECK: ldrb w0, [x0, [[REG]]]
211 entry:
212  %idx = getelementptr inbounds i16, i16* %ptr, i64 %off
213  %x = load i16, i16* %idx, align 8
214  %trunc = trunc i16 %x to i8
215  %ext = zext i8 %trunc to i64
216  ret i64 %ext
219 ; Check that we do use a narrower load, and so don't combine the shift, when
220 ; the loaded value is sign-extended.
222 define i64 @load_doubleword_trunc_word_sext(i64* %ptr, i64 %off) {
223 ; CHECK-LABEL: load_doubleword_trunc_word_sext:
224 ; CHECK: lsl [[REG:x[0-9]+]], x1, #3
225 ; CHECK: ldrsw x0, [x0, [[REG]]]
226 entry:
227   %idx = getelementptr inbounds i64, i64* %ptr, i64 %off
228   %x = load i64, i64* %idx, align 8
229   %trunc = trunc i64 %x to i32
230   %ext = sext i32 %trunc to i64
231   ret i64 %ext
234 define i64 @load_doubleword_trunc_halfword_sext(i64* %ptr, i64 %off) {
235 ; CHECK-LABEL: load_doubleword_trunc_halfword_sext:
236 ; CHECK: lsl [[REG:x[0-9]+]], x1, #3
237 ; CHECK: ldrsh x0, [x0, [[REG]]]
238 entry:
239   %idx = getelementptr inbounds i64, i64* %ptr, i64 %off
240   %x = load i64, i64* %idx, align 8
241   %trunc = trunc i64 %x to i16
242   %ext = sext i16 %trunc to i64
243   ret i64 %ext
246 define i64 @load_doubleword_trunc_byte_sext(i64* %ptr, i64 %off) {
247 ; CHECK-LABEL: load_doubleword_trunc_byte_sext:
248 ; CHECK: lsl [[REG:x[0-9]+]], x1, #3
249 ; CHECK: ldrsb x0, [x0, [[REG]]]
250 entry:
251   %idx = getelementptr inbounds i64, i64* %ptr, i64 %off
252   %x = load i64, i64* %idx, align 8
253   %trunc = trunc i64 %x to i8
254   %ext = sext i8 %trunc to i64
255   ret i64 %ext
258 define i64 @load_word_trunc_halfword_sext(i32* %ptr, i64 %off) {
259 ; CHECK-LABEL: load_word_trunc_halfword_sext:
260 ; CHECK: lsl [[REG:x[0-9]+]], x1, #2
261 ; CHECK: ldrsh x0, [x0, [[REG]]]
262 entry:
263   %idx = getelementptr inbounds i32, i32* %ptr, i64 %off
264   %x = load i32, i32* %idx, align 8
265   %trunc = trunc i32 %x to i16
266   %ext = sext i16 %trunc to i64
267   ret i64 %ext
270 define i64 @load_word_trunc_byte_sext(i32* %ptr, i64 %off) {
271 ; CHECK-LABEL: load_word_trunc_byte_sext:
272 ; CHECK: lsl [[REG:x[0-9]+]], x1, #2
273 ; CHECK: ldrsb x0, [x0, [[REG]]]
274 entry:
275  %idx = getelementptr inbounds i32, i32* %ptr, i64 %off
276  %x = load i32, i32* %idx, align 8
277  %trunc = trunc i32 %x to i8
278  %ext = sext i8 %trunc to i64
279  ret i64 %ext
282 define i64 @load_halfword_trunc_byte_sext(i16* %ptr, i64 %off) {
283 ; CHECK-LABEL: load_halfword_trunc_byte_sext:
284 ; CHECK: lsl [[REG:x[0-9]+]], x1, #1
285 ; CHECK: ldrsb x0, [x0, [[REG]]]
286 entry:
287  %idx = getelementptr inbounds i16, i16* %ptr, i64 %off
288  %x = load i16, i16* %idx, align 8
289  %trunc = trunc i16 %x to i8
290  %ext = sext i8 %trunc to i64
291  ret i64 %ext
294 ; Check that we don't combine the shift, and so will use a narrower load, when
295 ; the shift is used more than once.
297 define i32 @load_doubleword_trunc_word_reuse_shift(i64* %ptr, i64 %off) {
298 ; CHECK-LABEL: load_doubleword_trunc_word_reuse_shift:
299 ; CHECK: lsl x[[REG1:[0-9]+]], x1, #3
300 ; CHECK: ldr w[[REG2:[0-9]+]], [x0, x[[REG1]]]
301 ; CHECL: add w0, w[[REG2]], w[[REG1]]
302 entry:
303   %idx = getelementptr inbounds i64, i64* %ptr, i64 %off
304   %x = load i64, i64* %idx, align 8
305   %trunc = trunc i64 %x to i32
306   %lsl = shl i64 %off, 3
307   %lsl.trunc = trunc i64 %lsl to i32
308   %add = add i32 %trunc, %lsl.trunc
309   ret i32 %add
312 define i16 @load_doubleword_trunc_halfword_reuse_shift(i64* %ptr, i64 %off) {
313 ; CHECK-LABEL: load_doubleword_trunc_halfword_reuse_shift:
314 ; CHECK: lsl x[[REG1:[0-9]+]], x1, #3
315 ; CHECK: ldrh w[[REG2:[0-9]+]], [x0, x[[REG1]]]
316 ; CHECK: add w0, w[[REG2]], w[[REG1]]
317 entry:
318   %idx = getelementptr inbounds i64, i64* %ptr, i64 %off
319   %x = load i64, i64* %idx, align 8
320   %trunc = trunc i64 %x to i16
321   %lsl = shl i64 %off, 3
322   %lsl.trunc = trunc i64 %lsl to i16
323   %add = add i16 %trunc, %lsl.trunc
324   ret i16 %add
327 define i8 @load_doubleword_trunc_byte_reuse_shift(i64* %ptr, i64 %off) {
328 ; CHECK-LABEL: load_doubleword_trunc_byte_reuse_shift:
329 ; CHECK: lsl x[[REG1:[0-9]+]], x1, #3
330 ; CHECK: ldrb w[[REG2:[0-9]+]], [x0, x[[REG1]]]
331 ; CHECK: add w0, w[[REG2]], w[[REG1]]
332 entry:
333   %idx = getelementptr inbounds i64, i64* %ptr, i64 %off
334   %x = load i64, i64* %idx, align 8
335   %trunc = trunc i64 %x to i8
336   %lsl = shl i64 %off, 3
337   %lsl.trunc = trunc i64 %lsl to i8
338   %add = add i8 %trunc, %lsl.trunc
339   ret i8 %add
342 define i16 @load_word_trunc_halfword_reuse_shift(i32* %ptr, i64 %off) {
343 entry:
344 ; CHECK-LABEL: load_word_trunc_halfword_reuse_shift:
345 ; CHECK: lsl x[[REG1:[0-9]+]], x1, #2
346 ; CHECK: ldrh w[[REG2:[0-9]+]], [x0, x[[REG1]]]
347 ; CHECK: add w0, w[[REG2]], w[[REG1]]
348   %idx = getelementptr inbounds i32, i32* %ptr, i64 %off
349   %x = load i32, i32* %idx, align 8
350   %trunc = trunc i32 %x to i16
351   %lsl = shl i64 %off, 2
352   %lsl.trunc = trunc i64 %lsl to i16
353   %add = add i16 %trunc, %lsl.trunc
354   ret i16 %add
357 define i8 @load_word_trunc_byte_reuse_shift(i32* %ptr, i64 %off) {
358 ; CHECK-LABEL: load_word_trunc_byte_reuse_shift:
359 ; CHECK: lsl x[[REG1:[0-9]+]], x1, #2
360 ; CHECK: ldrb w[[REG2:[0-9]+]], [x0, x[[REG1]]]
361 ; CHECK: add w0, w[[REG2]], w[[REG1]]
362 entry:
363   %idx = getelementptr inbounds i32, i32* %ptr, i64 %off
364   %x = load i32, i32* %idx, align 8
365   %trunc = trunc i32 %x to i8
366   %lsl = shl i64 %off, 2
367   %lsl.trunc = trunc i64 %lsl to i8
368   %add = add i8 %trunc, %lsl.trunc
369   ret i8 %add
372 define i8 @load_halfword_trunc_byte_reuse_shift(i16* %ptr, i64 %off) {
373 ; CHECK-LABEL: load_halfword_trunc_byte_reuse_shift:
374 ; CHECK: lsl x[[REG1:[0-9]+]], x1, #1
375 ; CHECK: ldrb w[[REG2:[0-9]+]], [x0, x[[REG1]]]
376 ; CHECK: add w0, w[[REG2]], w[[REG1]]
377 entry:
378   %idx = getelementptr inbounds i16, i16* %ptr, i64 %off
379   %x = load i16, i16* %idx, align 8
380   %trunc = trunc i16 %x to i8
381   %lsl = shl i64 %off, 1
382   %lsl.trunc = trunc i64 %lsl to i8
383   %add = add i8 %trunc, %lsl.trunc
384   ret i8 %add