xref: /llvm-project/llvm/test/CodeGen/AArch64/addsub-constant-folding.ll (revision db158c7c830807caeeb0691739c41f1d522029e9)
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc < %s -mtriple=aarch64-unknown-unknown | FileCheck %s
3
4declare void @use(i32 %arg)
5declare void @vec_use(<4 x i32> %arg)
6
7; (x+c1)+c2
8
9define i32 @add_const_add_const(i32 %arg) {
10; CHECK-LABEL: add_const_add_const:
11; CHECK:       // %bb.0:
12; CHECK-NEXT:    add w0, w0, #10
13; CHECK-NEXT:    ret
14  %t0 = add i32 %arg, 8
15  %t1 = add i32 %t0, 2
16  ret i32 %t1
17}
18
19define i32 @add_const_add_const_extrause(i32 %arg) {
20; CHECK-LABEL: add_const_add_const_extrause:
21; CHECK:       // %bb.0:
22; CHECK-NEXT:    stp x30, x19, [sp, #-16]! // 16-byte Folded Spill
23; CHECK-NEXT:    .cfi_def_cfa_offset 16
24; CHECK-NEXT:    .cfi_offset w19, -8
25; CHECK-NEXT:    .cfi_offset w30, -16
26; CHECK-NEXT:    mov w19, w0
27; CHECK-NEXT:    add w0, w0, #8
28; CHECK-NEXT:    bl use
29; CHECK-NEXT:    add w0, w19, #10
30; CHECK-NEXT:    ldp x30, x19, [sp], #16 // 16-byte Folded Reload
31; CHECK-NEXT:    ret
32  %t0 = add i32 %arg, 8
33  call void @use(i32 %t0)
34  %t1 = add i32 %t0, 2
35  ret i32 %t1
36}
37
38define <4 x i32> @vec_add_const_add_const(<4 x i32> %arg) {
39; CHECK-LABEL: vec_add_const_add_const:
40; CHECK:       // %bb.0:
41; CHECK-NEXT:    movi v1.4s, #10
42; CHECK-NEXT:    add v0.4s, v0.4s, v1.4s
43; CHECK-NEXT:    ret
44  %t0 = add <4 x i32> %arg, <i32 8, i32 8, i32 8, i32 8>
45  %t1 = add <4 x i32> %t0, <i32 2, i32 2, i32 2, i32 2>
46  ret <4 x i32> %t1
47}
48
49define <4 x i32> @vec_add_const_add_const_extrause(<4 x i32> %arg) {
50; CHECK-LABEL: vec_add_const_add_const_extrause:
51; CHECK:       // %bb.0:
52; CHECK-NEXT:    sub sp, sp, #32
53; CHECK-NEXT:    str x30, [sp, #16] // 8-byte Folded Spill
54; CHECK-NEXT:    .cfi_def_cfa_offset 32
55; CHECK-NEXT:    .cfi_offset w30, -16
56; CHECK-NEXT:    movi v1.4s, #8
57; CHECK-NEXT:    str q0, [sp] // 16-byte Folded Spill
58; CHECK-NEXT:    add v0.4s, v0.4s, v1.4s
59; CHECK-NEXT:    bl vec_use
60; CHECK-NEXT:    movi v0.4s, #10
61; CHECK-NEXT:    ldr q1, [sp] // 16-byte Folded Reload
62; CHECK-NEXT:    ldr x30, [sp, #16] // 8-byte Folded Reload
63; CHECK-NEXT:    add v0.4s, v1.4s, v0.4s
64; CHECK-NEXT:    add sp, sp, #32
65; CHECK-NEXT:    ret
66  %t0 = add <4 x i32> %arg, <i32 8, i32 8, i32 8, i32 8>
67  call void @vec_use(<4 x i32> %t0)
68  %t1 = add <4 x i32> %t0, <i32 2, i32 2, i32 2, i32 2>
69  ret <4 x i32> %t1
70}
71
72define <4 x i32> @vec_add_const_add_const_nonsplat(<4 x i32> %arg) {
73; CHECK-LABEL: vec_add_const_add_const_nonsplat:
74; CHECK:       // %bb.0:
75; CHECK-NEXT:    adrp x8, .LCPI4_0
76; CHECK-NEXT:    ldr q1, [x8, :lo12:.LCPI4_0]
77; CHECK-NEXT:    add v0.4s, v0.4s, v1.4s
78; CHECK-NEXT:    ret
79  %t0 = add <4 x i32> %arg, <i32 21, i32 undef, i32 8, i32 8>
80  %t1 = add <4 x i32> %t0, <i32 2, i32 3, i32 undef, i32 2>
81  ret <4 x i32> %t1
82}
83
84; (x+c1)-c2
85
86define i32 @add_const_sub_const(i32 %arg) {
87; CHECK-LABEL: add_const_sub_const:
88; CHECK:       // %bb.0:
89; CHECK-NEXT:    add w0, w0, #6
90; CHECK-NEXT:    ret
91  %t0 = add i32 %arg, 8
92  %t1 = sub i32 %t0, 2
93  ret i32 %t1
94}
95
96define i32 @add_const_sub_const_extrause(i32 %arg) {
97; CHECK-LABEL: add_const_sub_const_extrause:
98; CHECK:       // %bb.0:
99; CHECK-NEXT:    stp x30, x19, [sp, #-16]! // 16-byte Folded Spill
100; CHECK-NEXT:    .cfi_def_cfa_offset 16
101; CHECK-NEXT:    .cfi_offset w19, -8
102; CHECK-NEXT:    .cfi_offset w30, -16
103; CHECK-NEXT:    mov w19, w0
104; CHECK-NEXT:    add w0, w0, #8
105; CHECK-NEXT:    bl use
106; CHECK-NEXT:    add w0, w19, #6
107; CHECK-NEXT:    ldp x30, x19, [sp], #16 // 16-byte Folded Reload
108; CHECK-NEXT:    ret
109  %t0 = add i32 %arg, 8
110  call void @use(i32 %t0)
111  %t1 = sub i32 %t0, 2
112  ret i32 %t1
113}
114
115define <4 x i32> @vec_add_const_sub_const(<4 x i32> %arg) {
116; CHECK-LABEL: vec_add_const_sub_const:
117; CHECK:       // %bb.0:
118; CHECK-NEXT:    movi v1.4s, #6
119; CHECK-NEXT:    add v0.4s, v0.4s, v1.4s
120; CHECK-NEXT:    ret
121  %t0 = add <4 x i32> %arg, <i32 8, i32 8, i32 8, i32 8>
122  %t1 = sub <4 x i32> %t0, <i32 2, i32 2, i32 2, i32 2>
123  ret <4 x i32> %t1
124}
125
126define <4 x i32> @vec_add_const_sub_const_extrause(<4 x i32> %arg) {
127; CHECK-LABEL: vec_add_const_sub_const_extrause:
128; CHECK:       // %bb.0:
129; CHECK-NEXT:    sub sp, sp, #32
130; CHECK-NEXT:    str x30, [sp, #16] // 8-byte Folded Spill
131; CHECK-NEXT:    .cfi_def_cfa_offset 32
132; CHECK-NEXT:    .cfi_offset w30, -16
133; CHECK-NEXT:    movi v1.4s, #8
134; CHECK-NEXT:    str q0, [sp] // 16-byte Folded Spill
135; CHECK-NEXT:    add v0.4s, v0.4s, v1.4s
136; CHECK-NEXT:    bl vec_use
137; CHECK-NEXT:    movi v0.4s, #6
138; CHECK-NEXT:    ldr q1, [sp] // 16-byte Folded Reload
139; CHECK-NEXT:    ldr x30, [sp, #16] // 8-byte Folded Reload
140; CHECK-NEXT:    add v0.4s, v1.4s, v0.4s
141; CHECK-NEXT:    add sp, sp, #32
142; CHECK-NEXT:    ret
143  %t0 = add <4 x i32> %arg, <i32 8, i32 8, i32 8, i32 8>
144  call void @vec_use(<4 x i32> %t0)
145  %t1 = sub <4 x i32> %t0, <i32 2, i32 2, i32 2, i32 2>
146  ret <4 x i32> %t1
147}
148
149define <4 x i32> @vec_add_const_sub_const_nonsplat(<4 x i32> %arg) {
150; CHECK-LABEL: vec_add_const_sub_const_nonsplat:
151; CHECK:       // %bb.0:
152; CHECK-NEXT:    adrp x8, .LCPI9_0
153; CHECK-NEXT:    ldr q1, [x8, :lo12:.LCPI9_0]
154; CHECK-NEXT:    add v0.4s, v0.4s, v1.4s
155; CHECK-NEXT:    ret
156  %t0 = add <4 x i32> %arg, <i32 21, i32 undef, i32 8, i32 8>
157  %t1 = sub <4 x i32> %t0, <i32 2, i32 3, i32 undef, i32 2>
158  ret <4 x i32> %t1
159}
160
161; c2-(x+c1)
162
163define i32 @add_const_const_sub(i32 %arg) {
164; CHECK-LABEL: add_const_const_sub:
165; CHECK:       // %bb.0:
166; CHECK-NEXT:    mov w8, #-6 // =0xfffffffa
167; CHECK-NEXT:    sub w0, w8, w0
168; CHECK-NEXT:    ret
169  %t0 = add i32 %arg, 8
170  %t1 = sub i32 2, %t0
171  ret i32 %t1
172}
173
174define i32 @add_const_const_sub_extrause(i32 %arg) {
175; CHECK-LABEL: add_const_const_sub_extrause:
176; CHECK:       // %bb.0:
177; CHECK-NEXT:    stp x30, x19, [sp, #-16]! // 16-byte Folded Spill
178; CHECK-NEXT:    .cfi_def_cfa_offset 16
179; CHECK-NEXT:    .cfi_offset w19, -8
180; CHECK-NEXT:    .cfi_offset w30, -16
181; CHECK-NEXT:    mov w19, w0
182; CHECK-NEXT:    add w0, w0, #8
183; CHECK-NEXT:    bl use
184; CHECK-NEXT:    mov w8, #-6 // =0xfffffffa
185; CHECK-NEXT:    sub w0, w8, w19
186; CHECK-NEXT:    ldp x30, x19, [sp], #16 // 16-byte Folded Reload
187; CHECK-NEXT:    ret
188  %t0 = add i32 %arg, 8
189  call void @use(i32 %t0)
190  %t1 = sub i32 2, %t0
191  ret i32 %t1
192}
193
194define <4 x i32> @vec_add_const_const_sub(<4 x i32> %arg) {
195; CHECK-LABEL: vec_add_const_const_sub:
196; CHECK:       // %bb.0:
197; CHECK-NEXT:    mvni v1.4s, #5
198; CHECK-NEXT:    sub v0.4s, v1.4s, v0.4s
199; CHECK-NEXT:    ret
200  %t0 = add <4 x i32> %arg, <i32 8, i32 8, i32 8, i32 8>
201  %t1 = sub <4 x i32> <i32 2, i32 2, i32 2, i32 2>, %t0
202  ret <4 x i32> %t1
203}
204
205define <4 x i32> @vec_add_const_const_sub_extrause(<4 x i32> %arg) {
206; CHECK-LABEL: vec_add_const_const_sub_extrause:
207; CHECK:       // %bb.0:
208; CHECK-NEXT:    sub sp, sp, #32
209; CHECK-NEXT:    str x30, [sp, #16] // 8-byte Folded Spill
210; CHECK-NEXT:    .cfi_def_cfa_offset 32
211; CHECK-NEXT:    .cfi_offset w30, -16
212; CHECK-NEXT:    movi v1.4s, #8
213; CHECK-NEXT:    str q0, [sp] // 16-byte Folded Spill
214; CHECK-NEXT:    add v0.4s, v0.4s, v1.4s
215; CHECK-NEXT:    bl vec_use
216; CHECK-NEXT:    mvni v0.4s, #5
217; CHECK-NEXT:    ldr q1, [sp] // 16-byte Folded Reload
218; CHECK-NEXT:    ldr x30, [sp, #16] // 8-byte Folded Reload
219; CHECK-NEXT:    sub v0.4s, v0.4s, v1.4s
220; CHECK-NEXT:    add sp, sp, #32
221; CHECK-NEXT:    ret
222  %t0 = add <4 x i32> %arg, <i32 8, i32 8, i32 8, i32 8>
223  call void @vec_use(<4 x i32> %t0)
224  %t1 = sub <4 x i32> <i32 2, i32 2, i32 2, i32 2>, %t0
225  ret <4 x i32> %t1
226}
227
228define <4 x i32> @vec_add_const_const_sub_nonsplat(<4 x i32> %arg) {
229; CHECK-LABEL: vec_add_const_const_sub_nonsplat:
230; CHECK:       // %bb.0:
231; CHECK-NEXT:    adrp x8, .LCPI14_0
232; CHECK-NEXT:    ldr q1, [x8, :lo12:.LCPI14_0]
233; CHECK-NEXT:    sub v0.4s, v1.4s, v0.4s
234; CHECK-NEXT:    ret
235  %t0 = add <4 x i32> %arg, <i32 21, i32 undef, i32 8, i32 8>
236  %t1 = sub <4 x i32> <i32 2, i32 3, i32 undef, i32 2>, %t0
237  ret <4 x i32> %t1
238}
239
240; (x-c1)+c2
241
242define i32 @sub_const_add_const(i32 %arg) {
243; CHECK-LABEL: sub_const_add_const:
244; CHECK:       // %bb.0:
245; CHECK-NEXT:    sub w0, w0, #6
246; CHECK-NEXT:    ret
247  %t0 = sub i32 %arg, 8
248  %t1 = add i32 %t0, 2
249  ret i32 %t1
250}
251
252define i32 @sub_const_add_const_extrause(i32 %arg) {
253; CHECK-LABEL: sub_const_add_const_extrause:
254; CHECK:       // %bb.0:
255; CHECK-NEXT:    stp x30, x19, [sp, #-16]! // 16-byte Folded Spill
256; CHECK-NEXT:    .cfi_def_cfa_offset 16
257; CHECK-NEXT:    .cfi_offset w19, -8
258; CHECK-NEXT:    .cfi_offset w30, -16
259; CHECK-NEXT:    mov w19, w0
260; CHECK-NEXT:    sub w0, w0, #8
261; CHECK-NEXT:    bl use
262; CHECK-NEXT:    sub w0, w19, #6
263; CHECK-NEXT:    ldp x30, x19, [sp], #16 // 16-byte Folded Reload
264; CHECK-NEXT:    ret
265  %t0 = sub i32 %arg, 8
266  call void @use(i32 %t0)
267  %t1 = add i32 %t0, 2
268  ret i32 %t1
269}
270
271define <4 x i32> @vec_sub_const_add_const(<4 x i32> %arg) {
272; CHECK-LABEL: vec_sub_const_add_const:
273; CHECK:       // %bb.0:
274; CHECK-NEXT:    mvni v1.4s, #5
275; CHECK-NEXT:    add v0.4s, v0.4s, v1.4s
276; CHECK-NEXT:    ret
277  %t0 = sub <4 x i32> %arg, <i32 8, i32 8, i32 8, i32 8>
278  %t1 = add <4 x i32> %t0, <i32 2, i32 2, i32 2, i32 2>
279  ret <4 x i32> %t1
280}
281
282define <4 x i32> @vec_sub_const_add_const_extrause(<4 x i32> %arg) {
283; CHECK-LABEL: vec_sub_const_add_const_extrause:
284; CHECK:       // %bb.0:
285; CHECK-NEXT:    sub sp, sp, #32
286; CHECK-NEXT:    str x30, [sp, #16] // 8-byte Folded Spill
287; CHECK-NEXT:    .cfi_def_cfa_offset 32
288; CHECK-NEXT:    .cfi_offset w30, -16
289; CHECK-NEXT:    movi v1.4s, #8
290; CHECK-NEXT:    str q0, [sp] // 16-byte Folded Spill
291; CHECK-NEXT:    sub v0.4s, v0.4s, v1.4s
292; CHECK-NEXT:    bl vec_use
293; CHECK-NEXT:    mvni v0.4s, #5
294; CHECK-NEXT:    ldr q1, [sp] // 16-byte Folded Reload
295; CHECK-NEXT:    ldr x30, [sp, #16] // 8-byte Folded Reload
296; CHECK-NEXT:    add v0.4s, v1.4s, v0.4s
297; CHECK-NEXT:    add sp, sp, #32
298; CHECK-NEXT:    ret
299  %t0 = sub <4 x i32> %arg, <i32 8, i32 8, i32 8, i32 8>
300  call void @vec_use(<4 x i32> %t0)
301  %t1 = add <4 x i32> %t0, <i32 2, i32 2, i32 2, i32 2>
302  ret <4 x i32> %t1
303}
304
305define <4 x i32> @vec_sub_const_add_const_nonsplat(<4 x i32> %arg) {
306; CHECK-LABEL: vec_sub_const_add_const_nonsplat:
307; CHECK:       // %bb.0:
308; CHECK-NEXT:    adrp x8, .LCPI19_0
309; CHECK-NEXT:    ldr q1, [x8, :lo12:.LCPI19_0]
310; CHECK-NEXT:    add v0.4s, v0.4s, v1.4s
311; CHECK-NEXT:    ret
312  %t0 = sub <4 x i32> %arg, <i32 21, i32 undef, i32 8, i32 8>
313  %t1 = add <4 x i32> %t0, <i32 2, i32 3, i32 undef, i32 2>
314  ret <4 x i32> %t1
315}
316
317; (x-c1)-c2
318
319define i32 @sub_const_sub_const(i32 %arg) {
320; CHECK-LABEL: sub_const_sub_const:
321; CHECK:       // %bb.0:
322; CHECK-NEXT:    sub w0, w0, #10
323; CHECK-NEXT:    ret
324  %t0 = sub i32 %arg, 8
325  %t1 = sub i32 %t0, 2
326  ret i32 %t1
327}
328
329define i32 @sub_const_sub_const_extrause(i32 %arg) {
330; CHECK-LABEL: sub_const_sub_const_extrause:
331; CHECK:       // %bb.0:
332; CHECK-NEXT:    stp x30, x19, [sp, #-16]! // 16-byte Folded Spill
333; CHECK-NEXT:    .cfi_def_cfa_offset 16
334; CHECK-NEXT:    .cfi_offset w19, -8
335; CHECK-NEXT:    .cfi_offset w30, -16
336; CHECK-NEXT:    mov w19, w0
337; CHECK-NEXT:    sub w0, w0, #8
338; CHECK-NEXT:    bl use
339; CHECK-NEXT:    sub w0, w19, #10
340; CHECK-NEXT:    ldp x30, x19, [sp], #16 // 16-byte Folded Reload
341; CHECK-NEXT:    ret
342  %t0 = sub i32 %arg, 8
343  call void @use(i32 %t0)
344  %t1 = sub i32 %t0, 2
345  ret i32 %t1
346}
347
348define <4 x i32> @vec_sub_const_sub_const(<4 x i32> %arg) {
349; CHECK-LABEL: vec_sub_const_sub_const:
350; CHECK:       // %bb.0:
351; CHECK-NEXT:    movi v1.4s, #10
352; CHECK-NEXT:    sub v0.4s, v0.4s, v1.4s
353; CHECK-NEXT:    ret
354  %t0 = sub <4 x i32> %arg, <i32 8, i32 8, i32 8, i32 8>
355  %t1 = sub <4 x i32> %t0, <i32 2, i32 2, i32 2, i32 2>
356  ret <4 x i32> %t1
357}
358
359define <4 x i32> @vec_sub_const_sub_const_extrause(<4 x i32> %arg) {
360; CHECK-LABEL: vec_sub_const_sub_const_extrause:
361; CHECK:       // %bb.0:
362; CHECK-NEXT:    sub sp, sp, #32
363; CHECK-NEXT:    str x30, [sp, #16] // 8-byte Folded Spill
364; CHECK-NEXT:    .cfi_def_cfa_offset 32
365; CHECK-NEXT:    .cfi_offset w30, -16
366; CHECK-NEXT:    movi v1.4s, #8
367; CHECK-NEXT:    str q0, [sp] // 16-byte Folded Spill
368; CHECK-NEXT:    sub v0.4s, v0.4s, v1.4s
369; CHECK-NEXT:    bl vec_use
370; CHECK-NEXT:    movi v0.4s, #10
371; CHECK-NEXT:    ldr q1, [sp] // 16-byte Folded Reload
372; CHECK-NEXT:    ldr x30, [sp, #16] // 8-byte Folded Reload
373; CHECK-NEXT:    sub v0.4s, v1.4s, v0.4s
374; CHECK-NEXT:    add sp, sp, #32
375; CHECK-NEXT:    ret
376  %t0 = sub <4 x i32> %arg, <i32 8, i32 8, i32 8, i32 8>
377  call void @vec_use(<4 x i32> %t0)
378  %t1 = sub <4 x i32> %t0, <i32 2, i32 2, i32 2, i32 2>
379  ret <4 x i32> %t1
380}
381
382define <4 x i32> @vec_sub_const_sub_const_nonsplat(<4 x i32> %arg) {
383; CHECK-LABEL: vec_sub_const_sub_const_nonsplat:
384; CHECK:       // %bb.0:
385; CHECK-NEXT:    adrp x8, .LCPI24_0
386; CHECK-NEXT:    ldr q1, [x8, :lo12:.LCPI24_0]
387; CHECK-NEXT:    sub v0.4s, v0.4s, v1.4s
388; CHECK-NEXT:    ret
389  %t0 = sub <4 x i32> %arg, <i32 21, i32 undef, i32 8, i32 8>
390  %t1 = sub <4 x i32> %t0, <i32 2, i32 3, i32 undef, i32 2>
391  ret <4 x i32> %t1
392}
393
394; c2-(x-c1)
395
396define i32 @sub_const_const_sub(i32 %arg) {
397; CHECK-LABEL: sub_const_const_sub:
398; CHECK:       // %bb.0:
399; CHECK-NEXT:    mov w8, #10 // =0xa
400; CHECK-NEXT:    sub w0, w8, w0
401; CHECK-NEXT:    ret
402  %t0 = sub i32 %arg, 8
403  %t1 = sub i32 2, %t0
404  ret i32 %t1
405}
406
407define i32 @sub_const_const_sub_extrause(i32 %arg) {
408; CHECK-LABEL: sub_const_const_sub_extrause:
409; CHECK:       // %bb.0:
410; CHECK-NEXT:    stp x30, x19, [sp, #-16]! // 16-byte Folded Spill
411; CHECK-NEXT:    .cfi_def_cfa_offset 16
412; CHECK-NEXT:    .cfi_offset w19, -8
413; CHECK-NEXT:    .cfi_offset w30, -16
414; CHECK-NEXT:    mov w19, w0
415; CHECK-NEXT:    sub w0, w0, #8
416; CHECK-NEXT:    bl use
417; CHECK-NEXT:    mov w8, #10 // =0xa
418; CHECK-NEXT:    sub w0, w8, w19
419; CHECK-NEXT:    ldp x30, x19, [sp], #16 // 16-byte Folded Reload
420; CHECK-NEXT:    ret
421  %t0 = sub i32 %arg, 8
422  call void @use(i32 %t0)
423  %t1 = sub i32 2, %t0
424  ret i32 %t1
425}
426
427define <4 x i32> @vec_sub_const_const_sub(<4 x i32> %arg) {
428; CHECK-LABEL: vec_sub_const_const_sub:
429; CHECK:       // %bb.0:
430; CHECK-NEXT:    movi v1.4s, #10
431; CHECK-NEXT:    sub v0.4s, v1.4s, v0.4s
432; CHECK-NEXT:    ret
433  %t0 = sub <4 x i32> %arg, <i32 8, i32 8, i32 8, i32 8>
434  %t1 = sub <4 x i32> <i32 2, i32 2, i32 2, i32 2>, %t0
435  ret <4 x i32> %t1
436}
437
438define <4 x i32> @vec_sub_const_const_sub_extrause(<4 x i32> %arg) {
439; CHECK-LABEL: vec_sub_const_const_sub_extrause:
440; CHECK:       // %bb.0:
441; CHECK-NEXT:    sub sp, sp, #32
442; CHECK-NEXT:    str x30, [sp, #16] // 8-byte Folded Spill
443; CHECK-NEXT:    .cfi_def_cfa_offset 32
444; CHECK-NEXT:    .cfi_offset w30, -16
445; CHECK-NEXT:    movi v1.4s, #8
446; CHECK-NEXT:    sub v0.4s, v0.4s, v1.4s
447; CHECK-NEXT:    str q0, [sp] // 16-byte Folded Spill
448; CHECK-NEXT:    bl vec_use
449; CHECK-NEXT:    movi v0.4s, #2
450; CHECK-NEXT:    ldr q1, [sp] // 16-byte Folded Reload
451; CHECK-NEXT:    ldr x30, [sp, #16] // 8-byte Folded Reload
452; CHECK-NEXT:    sub v0.4s, v0.4s, v1.4s
453; CHECK-NEXT:    add sp, sp, #32
454; CHECK-NEXT:    ret
455  %t0 = sub <4 x i32> %arg, <i32 8, i32 8, i32 8, i32 8>
456  call void @vec_use(<4 x i32> %t0)
457  %t1 = sub <4 x i32> <i32 2, i32 2, i32 2, i32 2>, %t0
458  ret <4 x i32> %t1
459}
460
461define <4 x i32> @vec_sub_const_const_sub_nonsplat(<4 x i32> %arg) {
462; CHECK-LABEL: vec_sub_const_const_sub_nonsplat:
463; CHECK:       // %bb.0:
464; CHECK-NEXT:    adrp x8, .LCPI29_0
465; CHECK-NEXT:    ldr q1, [x8, :lo12:.LCPI29_0]
466; CHECK-NEXT:    sub v0.4s, v1.4s, v0.4s
467; CHECK-NEXT:    ret
468  %t0 = sub <4 x i32> %arg, <i32 21, i32 undef, i32 8, i32 8>
469  %t1 = sub <4 x i32> <i32 2, i32 3, i32 undef, i32 2>, %t0
470  ret <4 x i32> %t1
471}
472
473; (c1-x)+c2
474
475define i32 @const_sub_add_const(i32 %arg) {
476; CHECK-LABEL: const_sub_add_const:
477; CHECK:       // %bb.0:
478; CHECK-NEXT:    mov w8, #10 // =0xa
479; CHECK-NEXT:    sub w0, w8, w0
480; CHECK-NEXT:    ret
481  %t0 = sub i32 8, %arg
482  %t1 = add i32 %t0, 2
483  ret i32 %t1
484}
485
486define i32 @const_sub_add_const_extrause(i32 %arg) {
487; CHECK-LABEL: const_sub_add_const_extrause:
488; CHECK:       // %bb.0:
489; CHECK-NEXT:    stp x30, x19, [sp, #-16]! // 16-byte Folded Spill
490; CHECK-NEXT:    .cfi_def_cfa_offset 16
491; CHECK-NEXT:    .cfi_offset w19, -8
492; CHECK-NEXT:    .cfi_offset w30, -16
493; CHECK-NEXT:    mov w8, #8 // =0x8
494; CHECK-NEXT:    mov w19, w0
495; CHECK-NEXT:    sub w0, w8, w0
496; CHECK-NEXT:    bl use
497; CHECK-NEXT:    mov w8, #10 // =0xa
498; CHECK-NEXT:    sub w0, w8, w19
499; CHECK-NEXT:    ldp x30, x19, [sp], #16 // 16-byte Folded Reload
500; CHECK-NEXT:    ret
501  %t0 = sub i32 8, %arg
502  call void @use(i32 %t0)
503  %t1 = add i32 %t0, 2
504  ret i32 %t1
505}
506
507define <4 x i32> @vec_const_sub_add_const(<4 x i32> %arg) {
508; CHECK-LABEL: vec_const_sub_add_const:
509; CHECK:       // %bb.0:
510; CHECK-NEXT:    movi v1.4s, #10
511; CHECK-NEXT:    sub v0.4s, v1.4s, v0.4s
512; CHECK-NEXT:    ret
513  %t0 = sub <4 x i32> <i32 8, i32 8, i32 8, i32 8>, %arg
514  %t1 = add <4 x i32> %t0, <i32 2, i32 2, i32 2, i32 2>
515  ret <4 x i32> %t1
516}
517
518define <4 x i32> @vec_const_sub_add_const_extrause(<4 x i32> %arg) {
519; CHECK-LABEL: vec_const_sub_add_const_extrause:
520; CHECK:       // %bb.0:
521; CHECK-NEXT:    sub sp, sp, #32
522; CHECK-NEXT:    str x30, [sp, #16] // 8-byte Folded Spill
523; CHECK-NEXT:    .cfi_def_cfa_offset 32
524; CHECK-NEXT:    .cfi_offset w30, -16
525; CHECK-NEXT:    movi v1.4s, #8
526; CHECK-NEXT:    str q0, [sp] // 16-byte Folded Spill
527; CHECK-NEXT:    sub v0.4s, v1.4s, v0.4s
528; CHECK-NEXT:    bl vec_use
529; CHECK-NEXT:    movi v0.4s, #10
530; CHECK-NEXT:    ldr q1, [sp] // 16-byte Folded Reload
531; CHECK-NEXT:    ldr x30, [sp, #16] // 8-byte Folded Reload
532; CHECK-NEXT:    sub v0.4s, v0.4s, v1.4s
533; CHECK-NEXT:    add sp, sp, #32
534; CHECK-NEXT:    ret
535  %t0 = sub <4 x i32> <i32 8, i32 8, i32 8, i32 8>, %arg
536  call void @vec_use(<4 x i32> %t0)
537  %t1 = add <4 x i32> %t0, <i32 2, i32 2, i32 2, i32 2>
538  ret <4 x i32> %t1
539}
540
541define <4 x i32> @vec_const_sub_add_const_nonsplat(<4 x i32> %arg) {
542; CHECK-LABEL: vec_const_sub_add_const_nonsplat:
543; CHECK:       // %bb.0:
544; CHECK-NEXT:    adrp x8, .LCPI34_0
545; CHECK-NEXT:    ldr q1, [x8, :lo12:.LCPI34_0]
546; CHECK-NEXT:    sub v0.4s, v1.4s, v0.4s
547; CHECK-NEXT:    ret
548  %t0 = sub <4 x i32> <i32 21, i32 undef, i32 8, i32 8>, %arg
549  %t1 = add <4 x i32> %t0, <i32 2, i32 3, i32 undef, i32 2>
550  ret <4 x i32> %t1
551}
552
553; (c1-x)-c2
554
555define i32 @const_sub_sub_const(i32 %arg) {
556; CHECK-LABEL: const_sub_sub_const:
557; CHECK:       // %bb.0:
558; CHECK-NEXT:    mov w8, #6 // =0x6
559; CHECK-NEXT:    sub w0, w8, w0
560; CHECK-NEXT:    ret
561  %t0 = sub i32 8, %arg
562  %t1 = sub i32 %t0, 2
563  ret i32 %t1
564}
565
566define i32 @const_sub_sub_const_extrause(i32 %arg) {
567; CHECK-LABEL: const_sub_sub_const_extrause:
568; CHECK:       // %bb.0:
569; CHECK-NEXT:    stp x30, x19, [sp, #-16]! // 16-byte Folded Spill
570; CHECK-NEXT:    .cfi_def_cfa_offset 16
571; CHECK-NEXT:    .cfi_offset w19, -8
572; CHECK-NEXT:    .cfi_offset w30, -16
573; CHECK-NEXT:    mov w8, #8 // =0x8
574; CHECK-NEXT:    mov w19, w0
575; CHECK-NEXT:    sub w0, w8, w0
576; CHECK-NEXT:    bl use
577; CHECK-NEXT:    mov w8, #6 // =0x6
578; CHECK-NEXT:    sub w0, w8, w19
579; CHECK-NEXT:    ldp x30, x19, [sp], #16 // 16-byte Folded Reload
580; CHECK-NEXT:    ret
581  %t0 = sub i32 8, %arg
582  call void @use(i32 %t0)
583  %t1 = sub i32 %t0, 2
584  ret i32 %t1
585}
586
587define <4 x i32> @vec_const_sub_sub_const(<4 x i32> %arg) {
588; CHECK-LABEL: vec_const_sub_sub_const:
589; CHECK:       // %bb.0:
590; CHECK-NEXT:    movi v1.4s, #6
591; CHECK-NEXT:    sub v0.4s, v1.4s, v0.4s
592; CHECK-NEXT:    ret
593  %t0 = sub <4 x i32> <i32 8, i32 8, i32 8, i32 8>, %arg
594  %t1 = sub <4 x i32> %t0, <i32 2, i32 2, i32 2, i32 2>
595  ret <4 x i32> %t1
596}
597
598define <4 x i32> @vec_const_sub_sub_const_extrause(<4 x i32> %arg) {
599; CHECK-LABEL: vec_const_sub_sub_const_extrause:
600; CHECK:       // %bb.0:
601; CHECK-NEXT:    sub sp, sp, #32
602; CHECK-NEXT:    str x30, [sp, #16] // 8-byte Folded Spill
603; CHECK-NEXT:    .cfi_def_cfa_offset 32
604; CHECK-NEXT:    .cfi_offset w30, -16
605; CHECK-NEXT:    movi v1.4s, #8
606; CHECK-NEXT:    str q0, [sp] // 16-byte Folded Spill
607; CHECK-NEXT:    sub v0.4s, v1.4s, v0.4s
608; CHECK-NEXT:    bl vec_use
609; CHECK-NEXT:    movi v0.4s, #6
610; CHECK-NEXT:    ldr q1, [sp] // 16-byte Folded Reload
611; CHECK-NEXT:    ldr x30, [sp, #16] // 8-byte Folded Reload
612; CHECK-NEXT:    sub v0.4s, v0.4s, v1.4s
613; CHECK-NEXT:    add sp, sp, #32
614; CHECK-NEXT:    ret
615  %t0 = sub <4 x i32> <i32 8, i32 8, i32 8, i32 8>, %arg
616  call void @vec_use(<4 x i32> %t0)
617  %t1 = sub <4 x i32> %t0, <i32 2, i32 2, i32 2, i32 2>
618  ret <4 x i32> %t1
619}
620
621define <4 x i32> @vec_const_sub_sub_const_nonsplat(<4 x i32> %arg) {
622; CHECK-LABEL: vec_const_sub_sub_const_nonsplat:
623; CHECK:       // %bb.0:
624; CHECK-NEXT:    adrp x8, .LCPI39_0
625; CHECK-NEXT:    ldr q1, [x8, :lo12:.LCPI39_0]
626; CHECK-NEXT:    sub v0.4s, v1.4s, v0.4s
627; CHECK-NEXT:    ret
628  %t0 = sub <4 x i32> <i32 21, i32 undef, i32 8, i32 8>, %arg
629  %t1 = sub <4 x i32> %t0, <i32 2, i32 3, i32 undef, i32 2>
630  ret <4 x i32> %t1
631}
632
633; c2-(c1-x)
634
635define i32 @const_sub_const_sub(i32 %arg) {
636; CHECK-LABEL: const_sub_const_sub:
637; CHECK:       // %bb.0:
638; CHECK-NEXT:    sub w0, w0, #6
639; CHECK-NEXT:    ret
640  %t0 = sub i32 8, %arg
641  %t1 = sub i32 2, %t0
642  ret i32 %t1
643}
644
645define i32 @const_sub_const_sub_extrause(i32 %arg) {
646; CHECK-LABEL: const_sub_const_sub_extrause:
647; CHECK:       // %bb.0:
648; CHECK-NEXT:    stp x30, x19, [sp, #-16]! // 16-byte Folded Spill
649; CHECK-NEXT:    .cfi_def_cfa_offset 16
650; CHECK-NEXT:    .cfi_offset w19, -8
651; CHECK-NEXT:    .cfi_offset w30, -16
652; CHECK-NEXT:    mov w8, #8 // =0x8
653; CHECK-NEXT:    sub w19, w8, w0
654; CHECK-NEXT:    mov w0, w19
655; CHECK-NEXT:    bl use
656; CHECK-NEXT:    mov w8, #2 // =0x2
657; CHECK-NEXT:    sub w0, w8, w19
658; CHECK-NEXT:    ldp x30, x19, [sp], #16 // 16-byte Folded Reload
659; CHECK-NEXT:    ret
660  %t0 = sub i32 8, %arg
661  call void @use(i32 %t0)
662  %t1 = sub i32 2, %t0
663  ret i32 %t1
664}
665
666define <4 x i32> @vec_const_sub_const_sub(<4 x i32> %arg) {
667; CHECK-LABEL: vec_const_sub_const_sub:
668; CHECK:       // %bb.0:
669; CHECK-NEXT:    mvni v1.4s, #5
670; CHECK-NEXT:    add v0.4s, v0.4s, v1.4s
671; CHECK-NEXT:    ret
672  %t0 = sub <4 x i32> <i32 8, i32 8, i32 8, i32 8>, %arg
673  %t1 = sub <4 x i32> <i32 2, i32 2, i32 2, i32 2>, %t0
674  ret <4 x i32> %t1
675}
676
677define <4 x i32> @vec_const_sub_const_sub_extrause(<4 x i32> %arg) {
678; CHECK-LABEL: vec_const_sub_const_sub_extrause:
679; CHECK:       // %bb.0:
680; CHECK-NEXT:    sub sp, sp, #32
681; CHECK-NEXT:    str x30, [sp, #16] // 8-byte Folded Spill
682; CHECK-NEXT:    .cfi_def_cfa_offset 32
683; CHECK-NEXT:    .cfi_offset w30, -16
684; CHECK-NEXT:    movi v1.4s, #8
685; CHECK-NEXT:    sub v0.4s, v1.4s, v0.4s
686; CHECK-NEXT:    str q0, [sp] // 16-byte Folded Spill
687; CHECK-NEXT:    bl vec_use
688; CHECK-NEXT:    movi v0.4s, #2
689; CHECK-NEXT:    ldr q1, [sp] // 16-byte Folded Reload
690; CHECK-NEXT:    ldr x30, [sp, #16] // 8-byte Folded Reload
691; CHECK-NEXT:    sub v0.4s, v0.4s, v1.4s
692; CHECK-NEXT:    add sp, sp, #32
693; CHECK-NEXT:    ret
694  %t0 = sub <4 x i32> <i32 8, i32 8, i32 8, i32 8>, %arg
695  call void @vec_use(<4 x i32> %t0)
696  %t1 = sub <4 x i32> <i32 2, i32 2, i32 2, i32 2>, %t0
697  ret <4 x i32> %t1
698}
699
700define <4 x i32> @vec_const_sub_const_sub_nonsplat(<4 x i32> %arg) {
701; CHECK-LABEL: vec_const_sub_const_sub_nonsplat:
702; CHECK:       // %bb.0:
703; CHECK-NEXT:    adrp x8, .LCPI44_0
704; CHECK-NEXT:    ldr q1, [x8, :lo12:.LCPI44_0]
705; CHECK-NEXT:    add v0.4s, v0.4s, v1.4s
706; CHECK-NEXT:    ret
707  %t0 = sub <4 x i32> <i32 21, i32 undef, i32 8, i32 8>, %arg
708  %t1 = sub <4 x i32> <i32 2, i32 3, i32 undef, i32 2>, %t0
709  ret <4 x i32> %t1
710}
711