xref: /llvm-project/llvm/test/CodeGen/ARM/ssat.ll (revision bed1c7f061aa12417aa081e334afdba45767b938)
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc -mtriple=armv4t-eabi %s -o - | FileCheck %s --check-prefix=V4T
3; RUN: llc -mtriple=armv6t2-eabi %s -o - | FileCheck %s --check-prefix=V6T2
4
5; Check for several conditions that should result in SSAT.
6; For example, the base test is equivalent to
7; x < -k ? -k : (x > k ? k : x) in C. All patterns that bound x
8; to the interval [-k, k] where k is a power of 2 can be
9; transformed into SSAT. At the end there are some tests
10; checking that conditionals are not transformed if they don't
11; match the right pattern.
12
13;
14; Base tests with different bit widths
15;
16
17; x < -k ? -k : (x > k ? k : x)
18; 32-bit base test
19define i32 @sat_base_32bit(i32 %x) #0 {
20; V4T-LABEL: sat_base_32bit:
21; V4T:       @ %bb.0: @ %entry
22; V4T-NEXT:    ldr r1, .LCPI0_0
23; V4T-NEXT:    cmp r0, r1
24; V4T-NEXT:    movge r0, r1
25; V4T-NEXT:    mov r1, #1065353216
26; V4T-NEXT:    orr r1, r1, #-1073741824
27; V4T-NEXT:    cmn r0, #8388608
28; V4T-NEXT:    movle r0, r1
29; V4T-NEXT:    bx lr
30; V4T-NEXT:    .p2align 2
31; V4T-NEXT:  @ %bb.1:
32; V4T-NEXT:  .LCPI0_0:
33; V4T-NEXT:    .long 8388607 @ 0x7fffff
34;
35; V6T2-LABEL: sat_base_32bit:
36; V6T2:       @ %bb.0: @ %entry
37; V6T2-NEXT:    ssat r0, #24, r0
38; V6T2-NEXT:    bx lr
39entry:
40  %0 = icmp slt i32 %x, 8388607
41  %saturateUp = select i1 %0, i32 %x, i32 8388607
42  %1 = icmp sgt i32 %saturateUp, -8388608
43  %saturateLow = select i1 %1, i32 %saturateUp, i32 -8388608
44  ret i32 %saturateLow
45}
46
47; x < -k ? -k : (x > k ? k : x)
48; 16-bit base test
49define i16 @sat_base_16bit(i16 %x) #0 {
50; V4T-LABEL: sat_base_16bit:
51; V4T:       @ %bb.0: @ %entry
52; V4T-NEXT:    mov r2, #255
53; V4T-NEXT:    lsl r1, r0, #16
54; V4T-NEXT:    orr r2, r2, #1792
55; V4T-NEXT:    asr r1, r1, #16
56; V4T-NEXT:    cmp r1, r2
57; V4T-NEXT:    movge r0, r2
58; V4T-NEXT:    ldr r2, .LCPI1_0
59; V4T-NEXT:    lsl r1, r0, #16
60; V4T-NEXT:    asr r1, r1, #16
61; V4T-NEXT:    cmn r1, #2048
62; V4T-NEXT:    movle r0, r2
63; V4T-NEXT:    bx lr
64; V4T-NEXT:    .p2align 2
65; V4T-NEXT:  @ %bb.1:
66; V4T-NEXT:  .LCPI1_0:
67; V4T-NEXT:    .long 4294965248 @ 0xfffff800
68;
69; V6T2-LABEL: sat_base_16bit:
70; V6T2:       @ %bb.0: @ %entry
71; V6T2-NEXT:    sxth r1, r0
72; V6T2-NEXT:    movw r2, #2047
73; V6T2-NEXT:    cmp r1, r2
74; V6T2-NEXT:    movge r0, r2
75; V6T2-NEXT:    movw r2, #63488
76; V6T2-NEXT:    sxth r1, r0
77; V6T2-NEXT:    movt r2, #65535
78; V6T2-NEXT:    cmn r1, #2048
79; V6T2-NEXT:    movle r0, r2
80; V6T2-NEXT:    bx lr
81entry:
82  %0 = icmp slt i16 %x, 2047
83  %saturateUp = select i1 %0, i16 %x, i16 2047
84  %1 = icmp sgt i16 %saturateUp, -2048
85  %saturateLow = select i1 %1, i16 %saturateUp, i16 -2048
86  ret i16 %saturateLow
87}
88
89; x < -k ? -k : (x > k ? k : x)
90; 8-bit base test
91define i8 @sat_base_8bit(i8 %x) #0 {
92; V4T-LABEL: sat_base_8bit:
93; V4T:       @ %bb.0: @ %entry
94; V4T-NEXT:    lsl r1, r0, #24
95; V4T-NEXT:    asr r1, r1, #24
96; V4T-NEXT:    cmp r1, #31
97; V4T-NEXT:    movge r0, #31
98; V4T-NEXT:    lsl r1, r0, #24
99; V4T-NEXT:    asr r1, r1, #24
100; V4T-NEXT:    cmn r1, #32
101; V4T-NEXT:    mvnle r0, #31
102; V4T-NEXT:    bx lr
103;
104; V6T2-LABEL: sat_base_8bit:
105; V6T2:       @ %bb.0: @ %entry
106; V6T2-NEXT:    sxtb r1, r0
107; V6T2-NEXT:    cmp r1, #31
108; V6T2-NEXT:    movge r0, #31
109; V6T2-NEXT:    sxtb r1, r0
110; V6T2-NEXT:    cmn r1, #32
111; V6T2-NEXT:    mvnle r0, #31
112; V6T2-NEXT:    bx lr
113entry:
114  %0 = icmp slt i8 %x, 31
115  %saturateUp = select i1 %0, i8 %x, i8 31
116  %1 = icmp sgt i8 %saturateUp, -32
117  %saturateLow = select i1 %1, i8 %saturateUp, i8 -32
118  ret i8 %saturateLow
119}
120
121;
122; Tests where the conditionals that check for upper and lower bounds,
123; or the < and > operators, are arranged in different ways. Only some
124; of the possible combinations that lead to SSAT are tested.
125;
126
127; x < -k ? -k : (x < k ? x : k)
128define i32 @sat_lower_upper_1(i32 %x) #0 {
129; V4T-LABEL: sat_lower_upper_1:
130; V4T:       @ %bb.0: @ %entry
131; V4T-NEXT:    ldr r1, .LCPI3_0
132; V4T-NEXT:    cmp r0, r1
133; V4T-NEXT:    movge r0, r1
134; V4T-NEXT:    mov r1, #1065353216
135; V4T-NEXT:    orr r1, r1, #-1073741824
136; V4T-NEXT:    cmn r0, #8388608
137; V4T-NEXT:    movle r0, r1
138; V4T-NEXT:    bx lr
139; V4T-NEXT:    .p2align 2
140; V4T-NEXT:  @ %bb.1:
141; V4T-NEXT:  .LCPI3_0:
142; V4T-NEXT:    .long 8388607 @ 0x7fffff
143;
144; V6T2-LABEL: sat_lower_upper_1:
145; V6T2:       @ %bb.0: @ %entry
146; V6T2-NEXT:    ssat r0, #24, r0
147; V6T2-NEXT:    bx lr
148entry:
149  %cmpUp = icmp slt i32 %x, 8388607
150  %saturateUp = select i1 %cmpUp, i32 %x, i32 8388607
151  %0 = icmp sgt i32 %saturateUp, -8388608
152  %saturateLow = select i1 %0, i32 %saturateUp, i32 -8388608
153  ret i32 %saturateLow
154}
155
156; x > -k ? (x > k ? k : x) : -k
157define i32 @sat_lower_upper_2(i32 %x) #0 {
158; V4T-LABEL: sat_lower_upper_2:
159; V4T:       @ %bb.0: @ %entry
160; V4T-NEXT:    ldr r1, .LCPI4_0
161; V4T-NEXT:    cmp r0, r1
162; V4T-NEXT:    movge r0, r1
163; V4T-NEXT:    mov r1, #1065353216
164; V4T-NEXT:    orr r1, r1, #-1073741824
165; V4T-NEXT:    cmn r0, #8388608
166; V4T-NEXT:    movle r0, r1
167; V4T-NEXT:    bx lr
168; V4T-NEXT:    .p2align 2
169; V4T-NEXT:  @ %bb.1:
170; V4T-NEXT:  .LCPI4_0:
171; V4T-NEXT:    .long 8388607 @ 0x7fffff
172;
173; V6T2-LABEL: sat_lower_upper_2:
174; V6T2:       @ %bb.0: @ %entry
175; V6T2-NEXT:    ssat r0, #24, r0
176; V6T2-NEXT:    bx lr
177entry:
178  %0 = icmp slt i32 %x, 8388607
179  %saturateUp = select i1 %0, i32 %x, i32 8388607
180  %1 = icmp sgt i32 %saturateUp, -8388608
181  %saturateLow = select i1 %1, i32 %saturateUp, i32 -8388608
182  ret i32 %saturateLow
183}
184
185; x < k ? (x < -k ? -k : x) : k
186define i32 @sat_upper_lower_1(i32 %x) #0 {
187; V4T-LABEL: sat_upper_lower_1:
188; V4T:       @ %bb.0: @ %entry
189; V4T-NEXT:    mov r1, #1065353216
190; V4T-NEXT:    cmn r0, #8388608
191; V4T-NEXT:    orr r1, r1, #-1073741824
192; V4T-NEXT:    movle r0, r1
193; V4T-NEXT:    ldr r1, .LCPI5_0
194; V4T-NEXT:    cmp r0, r1
195; V4T-NEXT:    movge r0, r1
196; V4T-NEXT:    bx lr
197; V4T-NEXT:    .p2align 2
198; V4T-NEXT:  @ %bb.1:
199; V4T-NEXT:  .LCPI5_0:
200; V4T-NEXT:    .long 8388607 @ 0x7fffff
201;
202; V6T2-LABEL: sat_upper_lower_1:
203; V6T2:       @ %bb.0: @ %entry
204; V6T2-NEXT:    ssat r0, #24, r0
205; V6T2-NEXT:    bx lr
206entry:
207  %0 = icmp sgt i32 %x, -8388608
208  %saturateLow = select i1 %0, i32 %x, i32 -8388608
209  %1 = icmp slt i32 %saturateLow, 8388607
210  %saturateUp = select i1 %1, i32 %saturateLow, i32 8388607
211  ret i32 %saturateUp
212}
213
214; x > k ? k : (x < -k ? -k : x)
215define i32 @sat_upper_lower_2(i32 %x) #0 {
216; V4T-LABEL: sat_upper_lower_2:
217; V4T:       @ %bb.0: @ %entry
218; V4T-NEXT:    mov r1, #1065353216
219; V4T-NEXT:    cmn r0, #8388608
220; V4T-NEXT:    orr r1, r1, #-1073741824
221; V4T-NEXT:    movle r0, r1
222; V4T-NEXT:    ldr r1, .LCPI6_0
223; V4T-NEXT:    cmp r0, r1
224; V4T-NEXT:    movge r0, r1
225; V4T-NEXT:    bx lr
226; V4T-NEXT:    .p2align 2
227; V4T-NEXT:  @ %bb.1:
228; V4T-NEXT:  .LCPI6_0:
229; V4T-NEXT:    .long 8388607 @ 0x7fffff
230;
231; V6T2-LABEL: sat_upper_lower_2:
232; V6T2:       @ %bb.0: @ %entry
233; V6T2-NEXT:    ssat r0, #24, r0
234; V6T2-NEXT:    bx lr
235entry:
236  %0 = icmp sgt i32 %x, -8388608
237  %saturateLow = select i1 %0, i32 %x, i32 -8388608
238  %1 = icmp slt i32 %saturateLow, 8388607
239  %saturateUp = select i1 %1, i32 %saturateLow, i32 8388607
240  ret i32 %saturateUp
241}
242
243; k < x ? k : (x > -k ? x : -k)
244define i32 @sat_upper_lower_3(i32 %x) #0 {
245; V4T-LABEL: sat_upper_lower_3:
246; V4T:       @ %bb.0: @ %entry
247; V4T-NEXT:    mov r1, #1065353216
248; V4T-NEXT:    cmn r0, #8388608
249; V4T-NEXT:    orr r1, r1, #-1073741824
250; V4T-NEXT:    movle r0, r1
251; V4T-NEXT:    ldr r1, .LCPI7_0
252; V4T-NEXT:    cmp r0, r1
253; V4T-NEXT:    movge r0, r1
254; V4T-NEXT:    bx lr
255; V4T-NEXT:    .p2align 2
256; V4T-NEXT:  @ %bb.1:
257; V4T-NEXT:  .LCPI7_0:
258; V4T-NEXT:    .long 8388607 @ 0x7fffff
259;
260; V6T2-LABEL: sat_upper_lower_3:
261; V6T2:       @ %bb.0: @ %entry
262; V6T2-NEXT:    ssat r0, #24, r0
263; V6T2-NEXT:    bx lr
264entry:
265  %cmpLow = icmp sgt i32 %x, -8388608
266  %saturateLow = select i1 %cmpLow, i32 %x, i32 -8388608
267  %0 = icmp slt i32 %saturateLow, 8388607
268  %saturateUp = select i1 %0, i32 %saturateLow, i32 8388607
269  ret i32 %saturateUp
270}
271
272;
273; Miscellanea
274;
275
276; Check that >= and <= work the same as > and <
277; k <= x ? k : (x >= -k ? x : -k)
278define i32 @sat_le_ge(i32 %x) #0 {
279; V4T-LABEL: sat_le_ge:
280; V4T:       @ %bb.0: @ %entry
281; V4T-NEXT:    mov r1, #1065353216
282; V4T-NEXT:    cmn r0, #8388608
283; V4T-NEXT:    orr r1, r1, #-1073741824
284; V4T-NEXT:    movle r0, r1
285; V4T-NEXT:    ldr r1, .LCPI8_0
286; V4T-NEXT:    cmp r0, r1
287; V4T-NEXT:    movge r0, r1
288; V4T-NEXT:    bx lr
289; V4T-NEXT:    .p2align 2
290; V4T-NEXT:  @ %bb.1:
291; V4T-NEXT:  .LCPI8_0:
292; V4T-NEXT:    .long 8388607 @ 0x7fffff
293;
294; V6T2-LABEL: sat_le_ge:
295; V6T2:       @ %bb.0: @ %entry
296; V6T2-NEXT:    ssat r0, #24, r0
297; V6T2-NEXT:    bx lr
298entry:
299  %0 = icmp sgt i32 %x, -8388608
300  %saturateLow = select i1 %0, i32 %x, i32 -8388608
301  %1 = icmp slt i32 %saturateLow, 8388607
302  %saturateUp = select i1 %1, i32 %saturateLow, i32 8388607
303  ret i32 %saturateUp
304}
305
306;
307; The following tests check for patterns that should not transform
308; into SSAT but are similar enough that could confuse the selector.
309;
310
311; x > k ? k : (x > -k ? -k : x)
312; First condition upper-saturates, second doesn't lower-saturate.
313define i32 @no_sat_missing_lower(i32 %x) #0 {
314; V4T-LABEL: no_sat_missing_lower:
315; V4T:       @ %bb.0: @ %entry
316; V4T-NEXT:    mov r2, #1065353216
317; V4T-NEXT:    cmn r0, #8388608
318; V4T-NEXT:    orr r2, r2, #-1073741824
319; V4T-NEXT:    ldr r1, .LCPI9_0
320; V4T-NEXT:    movlt r2, r0
321; V4T-NEXT:    cmp r0, #8388608
322; V4T-NEXT:    movlt r1, r2
323; V4T-NEXT:    mov r0, r1
324; V4T-NEXT:    bx lr
325; V4T-NEXT:    .p2align 2
326; V4T-NEXT:  @ %bb.1:
327; V4T-NEXT:  .LCPI9_0:
328; V4T-NEXT:    .long 8388607 @ 0x7fffff
329;
330; V6T2-LABEL: no_sat_missing_lower:
331; V6T2:       @ %bb.0: @ %entry
332; V6T2-NEXT:    movw r1, #0
333; V6T2-NEXT:    cmn r0, #8388608
334; V6T2-NEXT:    movt r1, #65408
335; V6T2-NEXT:    movlt r1, r0
336; V6T2-NEXT:    cmp r0, #8388608
337; V6T2-NEXT:    movwge r1, #65535
338; V6T2-NEXT:    movtge r1, #127
339; V6T2-NEXT:    mov r0, r1
340; V6T2-NEXT:    bx lr
341entry:
342  %cmpUp = icmp sgt i32 %x, 8388607
343  %0 = icmp slt i32 %x, -8388608
344  %saturateLow = select i1 %0, i32 %x, i32 -8388608
345  %saturateUp = select i1 %cmpUp, i32 8388607, i32 %saturateLow
346  ret i32 %saturateUp
347}
348
349; x < k ? k : (x < -k ? -k : x)
350; Second condition lower-saturates, first doesn't upper-saturate.
351define i32 @no_sat_missing_upper(i32 %x) #0 {
352; V4T-LABEL: no_sat_missing_upper:
353; V4T:       @ %bb.0: @ %entry
354; V4T-NEXT:    mov r1, #1065353216
355; V4T-NEXT:    ldr r2, .LCPI10_0
356; V4T-NEXT:    orr r1, r1, #-1073741824
357; V4T-NEXT:    cmn r0, #8388608
358; V4T-NEXT:    movgt r1, r0
359; V4T-NEXT:    cmp r0, r2
360; V4T-NEXT:    movlt r1, r2
361; V4T-NEXT:    mov r0, r1
362; V4T-NEXT:    bx lr
363; V4T-NEXT:    .p2align 2
364; V4T-NEXT:  @ %bb.1:
365; V4T-NEXT:  .LCPI10_0:
366; V4T-NEXT:    .long 8388607 @ 0x7fffff
367;
368; V6T2-LABEL: no_sat_missing_upper:
369; V6T2:       @ %bb.0: @ %entry
370; V6T2-NEXT:    movw r1, #0
371; V6T2-NEXT:    movw r2, #65535
372; V6T2-NEXT:    movt r1, #65408
373; V6T2-NEXT:    cmn r0, #8388608
374; V6T2-NEXT:    movgt r1, r0
375; V6T2-NEXT:    movt r2, #127
376; V6T2-NEXT:    cmp r0, r2
377; V6T2-NEXT:    movwlt r1, #65535
378; V6T2-NEXT:    movtlt r1, #127
379; V6T2-NEXT:    mov r0, r1
380; V6T2-NEXT:    bx lr
381entry:
382  %cmpUp = icmp slt i32 %x, 8388607
383  %0 = icmp sgt i32 %x, -8388608
384  %saturateLow = select i1 %0, i32 %x, i32 -8388608
385  %saturateUp = select i1 %cmpUp, i32 8388607, i32 %saturateLow
386  ret i32 %saturateUp
387}
388
389; Lower constant is different in the select and in the compare
390define i32 @no_sat_incorrect_constant(i32 %x) #0 {
391; V4T-LABEL: no_sat_incorrect_constant:
392; V4T:       @ %bb.0: @ %entry
393; V4T-NEXT:    mov r1, #1065353216
394; V4T-NEXT:    cmn r0, #8388608
395; V4T-NEXT:    orr r1, r1, #-1073741824
396; V4T-NEXT:    mov r2, r0
397; V4T-NEXT:    orrlt r2, r1, #1
398; V4T-NEXT:    ldr r1, .LCPI11_0
399; V4T-NEXT:    cmp r0, #8388608
400; V4T-NEXT:    movlt r1, r2
401; V4T-NEXT:    mov r0, r1
402; V4T-NEXT:    bx lr
403; V4T-NEXT:    .p2align 2
404; V4T-NEXT:  @ %bb.1:
405; V4T-NEXT:  .LCPI11_0:
406; V4T-NEXT:    .long 8388607 @ 0x7fffff
407;
408; V6T2-LABEL: no_sat_incorrect_constant:
409; V6T2:       @ %bb.0: @ %entry
410; V6T2-NEXT:    movw r2, #0
411; V6T2-NEXT:    cmn r0, #8388608
412; V6T2-NEXT:    mov r1, r0
413; V6T2-NEXT:    movt r2, #65408
414; V6T2-NEXT:    orrlt r1, r2, #1
415; V6T2-NEXT:    cmp r0, #8388608
416; V6T2-NEXT:    movwge r1, #65535
417; V6T2-NEXT:    movtge r1, #127
418; V6T2-NEXT:    mov r0, r1
419; V6T2-NEXT:    bx lr
420entry:
421  %cmpUp = icmp sgt i32 %x, 8388607
422  %cmpLow = icmp slt i32 %x, -8388608
423  %saturateLow = select i1 %cmpLow, i32 -8388607, i32 %x
424  %saturateUp = select i1 %cmpUp, i32 8388607, i32 %saturateLow
425  ret i32 %saturateUp
426}
427
428; The interval is not [k, ~k]
429define i32 @no_sat_incorrect_interval(i32 %x) #0 {
430; V4T-LABEL: no_sat_incorrect_interval:
431; V4T:       @ %bb.0: @ %entry
432; V4T-NEXT:    ldr r1, .LCPI12_0
433; V4T-NEXT:    cmp r0, r1
434; V4T-NEXT:    movle r0, r1
435; V4T-NEXT:    ldr r1, .LCPI12_1
436; V4T-NEXT:    cmp r0, r1
437; V4T-NEXT:    movge r0, r1
438; V4T-NEXT:    bx lr
439; V4T-NEXT:    .p2align 2
440; V4T-NEXT:  @ %bb.1:
441; V4T-NEXT:  .LCPI12_0:
442; V4T-NEXT:    .long 4275878552 @ 0xfedcba98
443; V4T-NEXT:  .LCPI12_1:
444; V4T-NEXT:    .long 8388607 @ 0x7fffff
445;
446; V6T2-LABEL: no_sat_incorrect_interval:
447; V6T2:       @ %bb.0: @ %entry
448; V6T2-NEXT:    movw r1, #47768
449; V6T2-NEXT:    movt r1, #65244
450; V6T2-NEXT:    cmp r0, r1
451; V6T2-NEXT:    movle r0, r1
452; V6T2-NEXT:    movw r1, #65535
453; V6T2-NEXT:    movt r1, #127
454; V6T2-NEXT:    cmp r0, r1
455; V6T2-NEXT:    movge r0, r1
456; V6T2-NEXT:    bx lr
457entry:
458  %0 = icmp sgt i32 %x, -19088744
459  %saturateLow = select i1 %0, i32 %x, i32 -19088744
460  %1 = icmp slt i32 %saturateLow, 8388607
461  %saturateUp = select i1 %1, i32 %saturateLow, i32 8388607
462  ret i32 %saturateUp
463}
464
465; The returned value (y) is not the same as the tested value (x).
466define i32 @no_sat_incorrect_return(i32 %x, i32 %y) #0 {
467; V4T-LABEL: no_sat_incorrect_return:
468; V4T:       @ %bb.0: @ %entry
469; V4T-NEXT:    mov r2, #1065353216
470; V4T-NEXT:    cmn r0, #8388608
471; V4T-NEXT:    orr r2, r2, #-1073741824
472; V4T-NEXT:    movge r2, r1
473; V4T-NEXT:    ldr r1, .LCPI13_0
474; V4T-NEXT:    cmp r0, #8388608
475; V4T-NEXT:    movlt r1, r2
476; V4T-NEXT:    mov r0, r1
477; V4T-NEXT:    bx lr
478; V4T-NEXT:    .p2align 2
479; V4T-NEXT:  @ %bb.1:
480; V4T-NEXT:  .LCPI13_0:
481; V4T-NEXT:    .long 8388607 @ 0x7fffff
482;
483; V6T2-LABEL: no_sat_incorrect_return:
484; V6T2:       @ %bb.0: @ %entry
485; V6T2-NEXT:    cmn r0, #8388608
486; V6T2-NEXT:    movwlt r1, #0
487; V6T2-NEXT:    movtlt r1, #65408
488; V6T2-NEXT:    cmp r0, #8388608
489; V6T2-NEXT:    movwge r1, #65535
490; V6T2-NEXT:    movtge r1, #127
491; V6T2-NEXT:    mov r0, r1
492; V6T2-NEXT:    bx lr
493entry:
494  %cmpUp = icmp sgt i32 %x, 8388607
495  %cmpLow = icmp slt i32 %x, -8388608
496  %saturateLow = select i1 %cmpLow, i32 -8388608, i32 %y
497  %saturateUp = select i1 %cmpUp, i32 8388607, i32 %saturateLow
498  ret i32 %saturateUp
499}
500
501; One of the values in a compare (y) is not the same as the rest
502; of the compare and select values (x).
503define i32 @no_sat_incorrect_compare(i32 %x, i32 %y) #0 {
504; V4T-LABEL: no_sat_incorrect_compare:
505; V4T:       @ %bb.0: @ %entry
506; V4T-NEXT:    mov r2, #1065353216
507; V4T-NEXT:    cmn r1, #8388608
508; V4T-NEXT:    orr r2, r2, #-1073741824
509; V4T-NEXT:    ldr r1, .LCPI14_0
510; V4T-NEXT:    movge r2, r0
511; V4T-NEXT:    cmp r0, #8388608
512; V4T-NEXT:    movlt r1, r2
513; V4T-NEXT:    mov r0, r1
514; V4T-NEXT:    bx lr
515; V4T-NEXT:    .p2align 2
516; V4T-NEXT:  @ %bb.1:
517; V4T-NEXT:  .LCPI14_0:
518; V4T-NEXT:    .long 8388607 @ 0x7fffff
519;
520; V6T2-LABEL: no_sat_incorrect_compare:
521; V6T2:       @ %bb.0: @ %entry
522; V6T2-NEXT:    cmn r1, #8388608
523; V6T2-NEXT:    mov r1, r0
524; V6T2-NEXT:    movwlt r1, #0
525; V6T2-NEXT:    movtlt r1, #65408
526; V6T2-NEXT:    cmp r0, #8388608
527; V6T2-NEXT:    movwge r1, #65535
528; V6T2-NEXT:    movtge r1, #127
529; V6T2-NEXT:    mov r0, r1
530; V6T2-NEXT:    bx lr
531entry:
532  %cmpUp = icmp sgt i32 %x, 8388607
533  %cmpLow = icmp slt i32 %y, -8388608
534  %saturateLow = select i1 %cmpLow, i32 -8388608, i32 %x
535  %saturateUp = select i1 %cmpUp, i32 8388607, i32 %saturateLow
536  ret i32 %saturateUp
537}
538
539define void @extended(i32 %xx, i16 signext %y, ptr nocapture %z) {
540; V4T-LABEL: extended:
541; V4T:       @ %bb.0: @ %entry
542; V4T-NEXT:    add r0, r1, r0, lsr #16
543; V4T-NEXT:    lsl r1, r0, #16
544; V4T-NEXT:    asr r1, r1, #16
545; V4T-NEXT:    cmp r1, #127
546; V4T-NEXT:    movge r0, #127
547; V4T-NEXT:    lsl r1, r0, #16
548; V4T-NEXT:    asr r1, r1, #16
549; V4T-NEXT:    cmn r1, #128
550; V4T-NEXT:    mvnle r0, #127
551; V4T-NEXT:    strb r0, [r2]
552; V4T-NEXT:    bx lr
553;
554; V6T2-LABEL: extended:
555; V6T2:       @ %bb.0: @ %entry
556; V6T2-NEXT:    add r0, r1, r0, lsr #16
557; V6T2-NEXT:    sxth r1, r0
558; V6T2-NEXT:    cmp r1, #127
559; V6T2-NEXT:    movge r0, #127
560; V6T2-NEXT:    sxth r1, r0
561; V6T2-NEXT:    cmn r1, #128
562; V6T2-NEXT:    mvnle r0, #127
563; V6T2-NEXT:    strb r0, [r2]
564; V6T2-NEXT:    bx lr
565entry:
566  %0 = lshr i32 %xx, 16
567  %1 = trunc i32 %0 to i16
568  %conv3 = add i16 %1, %y
569  %cmp.i = icmp slt i16 %conv3, 127
570  %cond.i = select i1 %cmp.i, i16 %conv3, i16 127
571  %cmp.i11 = icmp sgt i16 %cond.i, -128
572  %cond.i12 = select i1 %cmp.i11, i16 %cond.i, i16 -128
573  %conv5 = trunc i16 %cond.i12 to i8
574  store i8 %conv5, ptr %z, align 1
575  ret void
576}
577
578
579define i32 @formulated_valid(i32 %a) {
580; V4T-LABEL: formulated_valid:
581; V4T:       @ %bb.0:
582; V4T-NEXT:    lsl r1, r0, #16
583; V4T-NEXT:    asr r1, r1, #16
584; V4T-NEXT:    cmp r1, #127
585; V4T-NEXT:    movge r0, #127
586; V4T-NEXT:    lsl r1, r0, #16
587; V4T-NEXT:    asr r1, r1, #16
588; V4T-NEXT:    cmn r1, #128
589; V4T-NEXT:    mov r1, #255
590; V4T-NEXT:    mvnle r0, #127
591; V4T-NEXT:    orr r1, r1, #65280
592; V4T-NEXT:    and r0, r0, r1
593; V4T-NEXT:    bx lr
594;
595; V6T2-LABEL: formulated_valid:
596; V6T2:       @ %bb.0:
597; V6T2-NEXT:    sxth r1, r0
598; V6T2-NEXT:    cmp r1, #127
599; V6T2-NEXT:    movge r0, #127
600; V6T2-NEXT:    sxth r1, r0
601; V6T2-NEXT:    cmn r1, #128
602; V6T2-NEXT:    mvnle r0, #127
603; V6T2-NEXT:    uxth r0, r0
604; V6T2-NEXT:    bx lr
605  %x1 = trunc i32 %a to i16
606  %x2 = sext i16 %x1 to i32
607  %c1 = icmp slt i32 %x2, 127
608  %s1 = select i1 %c1, i32 %a, i32 127
609  %y1 = trunc i32 %s1 to i16
610  %y2 = sext i16 %y1 to i32
611  %c2 = icmp sgt i32 %y2, -128
612  %s2 = select i1 %c2, i32 %s1, i32 -128
613  %r = and i32 %s2, 65535
614  ret i32 %r
615}
616
617define i32 @formulated_invalid(i32 %a) {
618; V4T-LABEL: formulated_invalid:
619; V4T:       @ %bb.0:
620; V4T-NEXT:    lsl r1, r0, #16
621; V4T-NEXT:    asr r1, r1, #16
622; V4T-NEXT:    cmp r1, #127
623; V4T-NEXT:    movge r0, #127
624; V4T-NEXT:    lsl r1, r0, #16
625; V4T-NEXT:    asr r1, r1, #16
626; V4T-NEXT:    cmn r1, #128
627; V4T-NEXT:    mvnle r0, #127
628; V4T-NEXT:    bic r0, r0, #-16777216
629; V4T-NEXT:    bx lr
630;
631; V6T2-LABEL: formulated_invalid:
632; V6T2:       @ %bb.0:
633; V6T2-NEXT:    sxth r1, r0
634; V6T2-NEXT:    cmp r1, #127
635; V6T2-NEXT:    movge r0, #127
636; V6T2-NEXT:    sxth r1, r0
637; V6T2-NEXT:    cmn r1, #128
638; V6T2-NEXT:    mvnle r0, #127
639; V6T2-NEXT:    bic r0, r0, #-16777216
640; V6T2-NEXT:    bx lr
641  %x1 = trunc i32 %a to i16
642  %x2 = sext i16 %x1 to i32
643  %c1 = icmp slt i32 %x2, 127
644  %s1 = select i1 %c1, i32 %a, i32 127
645  %y1 = trunc i32 %s1 to i16
646  %y2 = sext i16 %y1 to i32
647  %c2 = icmp sgt i32 %y2, -128
648  %s2 = select i1 %c2, i32 %s1, i32 -128
649  %r = and i32 %s2, 16777215
650  ret i32 %r
651}
652
653
654define i32 @mm_sat_base_32bit(i32 %x) {
655; V4T-LABEL: mm_sat_base_32bit:
656; V4T:       @ %bb.0: @ %entry
657; V4T-NEXT:    ldr r1, .LCPI18_0
658; V4T-NEXT:    cmp r0, r1
659; V4T-NEXT:    movge r0, r1
660; V4T-NEXT:    mov r1, #1065353216
661; V4T-NEXT:    orr r1, r1, #-1073741824
662; V4T-NEXT:    cmn r0, #8388608
663; V4T-NEXT:    movle r0, r1
664; V4T-NEXT:    bx lr
665; V4T-NEXT:    .p2align 2
666; V4T-NEXT:  @ %bb.1:
667; V4T-NEXT:  .LCPI18_0:
668; V4T-NEXT:    .long 8388607 @ 0x7fffff
669;
670; V6T2-LABEL: mm_sat_base_32bit:
671; V6T2:       @ %bb.0: @ %entry
672; V6T2-NEXT:    ssat r0, #24, r0
673; V6T2-NEXT:    bx lr
674entry:
675  %0 = call i32 @llvm.smin.i32(i32 %x, i32 8388607)
676  %1 = call i32 @llvm.smax.i32(i32 %0, i32 -8388608)
677  ret i32 %1
678}
679
680define i16 @mm_sat_base_16bit(i16 %x) {
681; V4T-LABEL: mm_sat_base_16bit:
682; V4T:       @ %bb.0: @ %entry
683; V4T-NEXT:    mov r2, #255
684; V4T-NEXT:    lsl r0, r0, #16
685; V4T-NEXT:    orr r2, r2, #1792
686; V4T-NEXT:    asr r1, r0, #16
687; V4T-NEXT:    cmp r1, r2
688; V4T-NEXT:    asrlt r2, r0, #16
689; V4T-NEXT:    ldr r0, .LCPI19_0
690; V4T-NEXT:    cmn r2, #2048
691; V4T-NEXT:    movgt r0, r2
692; V4T-NEXT:    bx lr
693; V4T-NEXT:    .p2align 2
694; V4T-NEXT:  @ %bb.1:
695; V4T-NEXT:  .LCPI19_0:
696; V4T-NEXT:    .long 4294965248 @ 0xfffff800
697;
698; V6T2-LABEL: mm_sat_base_16bit:
699; V6T2:       @ %bb.0: @ %entry
700; V6T2-NEXT:    sxth r0, r0
701; V6T2-NEXT:    ssat r0, #12, r0
702; V6T2-NEXT:    bx lr
703entry:
704  %0 = call i16 @llvm.smin.i16(i16 %x, i16 2047)
705  %1 = call i16 @llvm.smax.i16(i16 %0, i16 -2048)
706  ret i16 %1
707}
708
709define i8 @mm_sat_base_8bit(i8 %x) {
710; V4T-LABEL: mm_sat_base_8bit:
711; V4T:       @ %bb.0: @ %entry
712; V4T-NEXT:    lsl r1, r0, #24
713; V4T-NEXT:    mov r0, #31
714; V4T-NEXT:    asr r2, r1, #24
715; V4T-NEXT:    cmp r2, #31
716; V4T-NEXT:    asrlt r0, r1, #24
717; V4T-NEXT:    cmn r0, #32
718; V4T-NEXT:    mvnle r0, #31
719; V4T-NEXT:    bx lr
720;
721; V6T2-LABEL: mm_sat_base_8bit:
722; V6T2:       @ %bb.0: @ %entry
723; V6T2-NEXT:    sxtb r0, r0
724; V6T2-NEXT:    ssat r0, #6, r0
725; V6T2-NEXT:    bx lr
726entry:
727  %0 = call i8 @llvm.smin.i8(i8 %x, i8 31)
728  %1 = call i8 @llvm.smax.i8(i8 %0, i8 -32)
729  ret i8 %1
730}
731
732define i32 @mm_sat_lower_upper_1(i32 %x) {
733; V4T-LABEL: mm_sat_lower_upper_1:
734; V4T:       @ %bb.0: @ %entry
735; V4T-NEXT:    ldr r1, .LCPI21_0
736; V4T-NEXT:    cmp r0, r1
737; V4T-NEXT:    movge r0, r1
738; V4T-NEXT:    mov r1, #1065353216
739; V4T-NEXT:    orr r1, r1, #-1073741824
740; V4T-NEXT:    cmn r0, #8388608
741; V4T-NEXT:    movle r0, r1
742; V4T-NEXT:    bx lr
743; V4T-NEXT:    .p2align 2
744; V4T-NEXT:  @ %bb.1:
745; V4T-NEXT:  .LCPI21_0:
746; V4T-NEXT:    .long 8388607 @ 0x7fffff
747;
748; V6T2-LABEL: mm_sat_lower_upper_1:
749; V6T2:       @ %bb.0: @ %entry
750; V6T2-NEXT:    ssat r0, #24, r0
751; V6T2-NEXT:    bx lr
752entry:
753  %0 = call i32 @llvm.smin.i32(i32 %x, i32 8388607)
754  %1 = call i32 @llvm.smax.i32(i32 %0, i32 -8388608)
755  ret i32 %1
756}
757
758define i32 @mm_sat_lower_upper_2(i32 %x) {
759; V4T-LABEL: mm_sat_lower_upper_2:
760; V4T:       @ %bb.0: @ %entry
761; V4T-NEXT:    ldr r1, .LCPI22_0
762; V4T-NEXT:    cmp r0, r1
763; V4T-NEXT:    movge r0, r1
764; V4T-NEXT:    mov r1, #1065353216
765; V4T-NEXT:    orr r1, r1, #-1073741824
766; V4T-NEXT:    cmn r0, #8388608
767; V4T-NEXT:    movle r0, r1
768; V4T-NEXT:    bx lr
769; V4T-NEXT:    .p2align 2
770; V4T-NEXT:  @ %bb.1:
771; V4T-NEXT:  .LCPI22_0:
772; V4T-NEXT:    .long 8388607 @ 0x7fffff
773;
774; V6T2-LABEL: mm_sat_lower_upper_2:
775; V6T2:       @ %bb.0: @ %entry
776; V6T2-NEXT:    ssat r0, #24, r0
777; V6T2-NEXT:    bx lr
778entry:
779  %0 = call i32 @llvm.smin.i32(i32 %x, i32 8388607)
780  %1 = call i32 @llvm.smax.i32(i32 %0, i32 -8388608)
781  ret i32 %1
782}
783
784define i32 @mm_sat_upper_lower_1(i32 %x) {
785; V4T-LABEL: mm_sat_upper_lower_1:
786; V4T:       @ %bb.0: @ %entry
787; V4T-NEXT:    mov r1, #1065353216
788; V4T-NEXT:    cmn r0, #8388608
789; V4T-NEXT:    orr r1, r1, #-1073741824
790; V4T-NEXT:    movle r0, r1
791; V4T-NEXT:    ldr r1, .LCPI23_0
792; V4T-NEXT:    cmp r0, r1
793; V4T-NEXT:    movge r0, r1
794; V4T-NEXT:    bx lr
795; V4T-NEXT:    .p2align 2
796; V4T-NEXT:  @ %bb.1:
797; V4T-NEXT:  .LCPI23_0:
798; V4T-NEXT:    .long 8388607 @ 0x7fffff
799;
800; V6T2-LABEL: mm_sat_upper_lower_1:
801; V6T2:       @ %bb.0: @ %entry
802; V6T2-NEXT:    ssat r0, #24, r0
803; V6T2-NEXT:    bx lr
804entry:
805  %0 = call i32 @llvm.smax.i32(i32 %x, i32 -8388608)
806  %1 = call i32 @llvm.smin.i32(i32 %0, i32 8388607)
807  ret i32 %1
808}
809
810define i32 @mm_sat_upper_lower_2(i32 %x) {
811; V4T-LABEL: mm_sat_upper_lower_2:
812; V4T:       @ %bb.0: @ %entry
813; V4T-NEXT:    mov r1, #1065353216
814; V4T-NEXT:    cmn r0, #8388608
815; V4T-NEXT:    orr r1, r1, #-1073741824
816; V4T-NEXT:    movle r0, r1
817; V4T-NEXT:    ldr r1, .LCPI24_0
818; V4T-NEXT:    cmp r0, r1
819; V4T-NEXT:    movge r0, r1
820; V4T-NEXT:    bx lr
821; V4T-NEXT:    .p2align 2
822; V4T-NEXT:  @ %bb.1:
823; V4T-NEXT:  .LCPI24_0:
824; V4T-NEXT:    .long 8388607 @ 0x7fffff
825;
826; V6T2-LABEL: mm_sat_upper_lower_2:
827; V6T2:       @ %bb.0: @ %entry
828; V6T2-NEXT:    ssat r0, #24, r0
829; V6T2-NEXT:    bx lr
830entry:
831  %0 = call i32 @llvm.smax.i32(i32 %x, i32 -8388608)
832  %1 = call i32 @llvm.smin.i32(i32 %0, i32 8388607)
833  ret i32 %1
834}
835
836define i32 @mm_sat_upper_lower_3(i32 %x) {
837; V4T-LABEL: mm_sat_upper_lower_3:
838; V4T:       @ %bb.0: @ %entry
839; V4T-NEXT:    mov r1, #1065353216
840; V4T-NEXT:    cmn r0, #8388608
841; V4T-NEXT:    orr r1, r1, #-1073741824
842; V4T-NEXT:    movle r0, r1
843; V4T-NEXT:    ldr r1, .LCPI25_0
844; V4T-NEXT:    cmp r0, r1
845; V4T-NEXT:    movge r0, r1
846; V4T-NEXT:    bx lr
847; V4T-NEXT:    .p2align 2
848; V4T-NEXT:  @ %bb.1:
849; V4T-NEXT:  .LCPI25_0:
850; V4T-NEXT:    .long 8388607 @ 0x7fffff
851;
852; V6T2-LABEL: mm_sat_upper_lower_3:
853; V6T2:       @ %bb.0: @ %entry
854; V6T2-NEXT:    ssat r0, #24, r0
855; V6T2-NEXT:    bx lr
856entry:
857  %0 = call i32 @llvm.smax.i32(i32 %x, i32 -8388608)
858  %1 = call i32 @llvm.smin.i32(i32 %0, i32 8388607)
859  ret i32 %1
860}
861
862define i32 @mm_sat_le_ge(i32 %x) {
863; V4T-LABEL: mm_sat_le_ge:
864; V4T:       @ %bb.0: @ %entry
865; V4T-NEXT:    mov r1, #1065353216
866; V4T-NEXT:    cmn r0, #8388608
867; V4T-NEXT:    orr r1, r1, #-1073741824
868; V4T-NEXT:    movle r0, r1
869; V4T-NEXT:    ldr r1, .LCPI26_0
870; V4T-NEXT:    cmp r0, r1
871; V4T-NEXT:    movge r0, r1
872; V4T-NEXT:    bx lr
873; V4T-NEXT:    .p2align 2
874; V4T-NEXT:  @ %bb.1:
875; V4T-NEXT:  .LCPI26_0:
876; V4T-NEXT:    .long 8388607 @ 0x7fffff
877;
878; V6T2-LABEL: mm_sat_le_ge:
879; V6T2:       @ %bb.0: @ %entry
880; V6T2-NEXT:    ssat r0, #24, r0
881; V6T2-NEXT:    bx lr
882entry:
883  %0 = call i32 @llvm.smax.i32(i32 %x, i32 -8388608)
884  %1 = call i32 @llvm.smin.i32(i32 %0, i32 8388607)
885  ret i32 %1
886}
887
888define i32 @mm_no_sat_incorrect_interval(i32 %x) {
889; V4T-LABEL: mm_no_sat_incorrect_interval:
890; V4T:       @ %bb.0: @ %entry
891; V4T-NEXT:    ldr r1, .LCPI27_0
892; V4T-NEXT:    cmp r0, r1
893; V4T-NEXT:    movle r0, r1
894; V4T-NEXT:    ldr r1, .LCPI27_1
895; V4T-NEXT:    cmp r0, r1
896; V4T-NEXT:    movge r0, r1
897; V4T-NEXT:    bx lr
898; V4T-NEXT:    .p2align 2
899; V4T-NEXT:  @ %bb.1:
900; V4T-NEXT:  .LCPI27_0:
901; V4T-NEXT:    .long 4275878552 @ 0xfedcba98
902; V4T-NEXT:  .LCPI27_1:
903; V4T-NEXT:    .long 8388607 @ 0x7fffff
904;
905; V6T2-LABEL: mm_no_sat_incorrect_interval:
906; V6T2:       @ %bb.0: @ %entry
907; V6T2-NEXT:    movw r1, #47768
908; V6T2-NEXT:    movt r1, #65244
909; V6T2-NEXT:    cmp r0, r1
910; V6T2-NEXT:    movle r0, r1
911; V6T2-NEXT:    movw r1, #65535
912; V6T2-NEXT:    movt r1, #127
913; V6T2-NEXT:    cmp r0, r1
914; V6T2-NEXT:    movge r0, r1
915; V6T2-NEXT:    bx lr
916entry:
917  %0 = call i32 @llvm.smax.i32(i32 %x, i32 -19088744)
918  %1 = call i32 @llvm.smin.i32(i32 %0, i32 8388607)
919  ret i32 %1
920}
921
922declare i32 @llvm.smin.i32(i32, i32)
923declare i32 @llvm.smax.i32(i32, i32)
924declare i16 @llvm.smin.i16(i16, i16)
925declare i16 @llvm.smax.i16(i16, i16)
926declare i8 @llvm.smin.i8(i8, i8)
927declare i8 @llvm.smax.i8(i8, i8)
928
929
930