1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc -mtriple=arm %s -o - | FileCheck %s --check-prefix=CHECK-ARM
3; RUN: llc -mtriple=thumb-eabi %s -o - | FileCheck %s --check-prefix=CHECK-T
4; RUN: llc -mtriple=thumb-eabi -mcpu=arm1156t2-s -mattr=+thumb2 %s -o - | FileCheck %s --check-prefix=CHECK-T2
5
6; Check for clipping against 0 that should result in bic
7;
8; Base tests with different bit widths
9
10; x < 0 ? 0 : x
11; 32-bit base test
12define i32 @sat0_base_32bit(i32 %x) #0 {
13; CHECK-ARM-LABEL: sat0_base_32bit:
14; CHECK-ARM:       @ %bb.0: @ %entry
15; CHECK-ARM-NEXT:    bic r0, r0, r0, asr #31
16; CHECK-ARM-NEXT:    mov pc, lr
17;
18; CHECK-T-LABEL: sat0_base_32bit:
19; CHECK-T:       @ %bb.0: @ %entry
20; CHECK-T-NEXT:    asrs r1, r0, #31
21; CHECK-T-NEXT:    bics r0, r1
22; CHECK-T-NEXT:    bx lr
23;
24; CHECK-T2-LABEL: sat0_base_32bit:
25; CHECK-T2:       @ %bb.0: @ %entry
26; CHECK-T2-NEXT:    bic.w r0, r0, r0, asr #31
27; CHECK-T2-NEXT:    bx lr
28entry:
29  %cmpLow = icmp slt i32 %x, 0
30  %saturateLow = select i1 %cmpLow, i32 0, i32 %x
31  ret i32 %saturateLow
32}
33
34; x < 0 ? 0 : x
35; 16-bit base test
36define i16 @sat0_base_16bit(i16 %x) #0 {
37; CHECK-ARM-LABEL: sat0_base_16bit:
38; CHECK-ARM:       @ %bb.0: @ %entry
39; CHECK-ARM-NEXT:    lsl r1, r0, #16
40; CHECK-ARM-NEXT:    asr r1, r1, #16
41; CHECK-ARM-NEXT:    cmp r1, #0
42; CHECK-ARM-NEXT:    movmi r0, #0
43; CHECK-ARM-NEXT:    mov pc, lr
44;
45; CHECK-T-LABEL: sat0_base_16bit:
46; CHECK-T:       @ %bb.0: @ %entry
47; CHECK-T-NEXT:    lsls r1, r0, #16
48; CHECK-T-NEXT:    asrs r1, r1, #16
49; CHECK-T-NEXT:    bpl .LBB1_2
50; CHECK-T-NEXT:  @ %bb.1:
51; CHECK-T-NEXT:    movs r0, #0
52; CHECK-T-NEXT:  .LBB1_2: @ %entry
53; CHECK-T-NEXT:    bx lr
54;
55; CHECK-T2-LABEL: sat0_base_16bit:
56; CHECK-T2:       @ %bb.0: @ %entry
57; CHECK-T2-NEXT:    sxth r1, r0
58; CHECK-T2-NEXT:    cmp r1, #0
59; CHECK-T2-NEXT:    it mi
60; CHECK-T2-NEXT:    movmi r0, #0
61; CHECK-T2-NEXT:    bx lr
62entry:
63  %cmpLow = icmp slt i16 %x, 0
64  %saturateLow = select i1 %cmpLow, i16 0, i16 %x
65  ret i16 %saturateLow
66}
67
68; x < 0 ? 0 : x
69; 8-bit base test
70define i8 @sat0_base_8bit(i8 %x) #0 {
71; CHECK-ARM-LABEL: sat0_base_8bit:
72; CHECK-ARM:       @ %bb.0: @ %entry
73; CHECK-ARM-NEXT:    lsl r1, r0, #24
74; CHECK-ARM-NEXT:    asr r1, r1, #24
75; CHECK-ARM-NEXT:    cmp r1, #0
76; CHECK-ARM-NEXT:    movmi r0, #0
77; CHECK-ARM-NEXT:    mov pc, lr
78;
79; CHECK-T-LABEL: sat0_base_8bit:
80; CHECK-T:       @ %bb.0: @ %entry
81; CHECK-T-NEXT:    lsls r1, r0, #24
82; CHECK-T-NEXT:    asrs r1, r1, #24
83; CHECK-T-NEXT:    bpl .LBB2_2
84; CHECK-T-NEXT:  @ %bb.1:
85; CHECK-T-NEXT:    movs r0, #0
86; CHECK-T-NEXT:  .LBB2_2: @ %entry
87; CHECK-T-NEXT:    bx lr
88;
89; CHECK-T2-LABEL: sat0_base_8bit:
90; CHECK-T2:       @ %bb.0: @ %entry
91; CHECK-T2-NEXT:    sxtb r1, r0
92; CHECK-T2-NEXT:    cmp r1, #0
93; CHECK-T2-NEXT:    it mi
94; CHECK-T2-NEXT:    movmi r0, #0
95; CHECK-T2-NEXT:    bx lr
96entry:
97  %cmpLow = icmp slt i8 %x, 0
98  %saturateLow = select i1 %cmpLow, i8 0, i8 %x
99  ret i8 %saturateLow
100}
101
102; Test where the conditional is formed in a different way
103
104; x > 0 ? x : 0
105define i32 @sat0_lower_1(i32 %x) #0 {
106; CHECK-ARM-LABEL: sat0_lower_1:
107; CHECK-ARM:       @ %bb.0: @ %entry
108; CHECK-ARM-NEXT:    bic r0, r0, r0, asr #31
109; CHECK-ARM-NEXT:    mov pc, lr
110;
111; CHECK-T-LABEL: sat0_lower_1:
112; CHECK-T:       @ %bb.0: @ %entry
113; CHECK-T-NEXT:    asrs r1, r0, #31
114; CHECK-T-NEXT:    bics r0, r1
115; CHECK-T-NEXT:    bx lr
116;
117; CHECK-T2-LABEL: sat0_lower_1:
118; CHECK-T2:       @ %bb.0: @ %entry
119; CHECK-T2-NEXT:    bic.w r0, r0, r0, asr #31
120; CHECK-T2-NEXT:    bx lr
121entry:
122  %cmpGt = icmp sgt i32 %x, 0
123  %saturateLow = select i1 %cmpGt, i32 %x, i32 0
124  ret i32 %saturateLow
125}
126
127
128; Check for clipping against -1 that should result in orr
129;
130; Base tests with different bit widths
131;
132
133; x < -1 ? -1 : x
134; 32-bit base test
135define i32 @sat1_base_32bit(i32 %x) #0 {
136; CHECK-ARM-LABEL: sat1_base_32bit:
137; CHECK-ARM:       @ %bb.0: @ %entry
138; CHECK-ARM-NEXT:    orr r0, r0, r0, asr #31
139; CHECK-ARM-NEXT:    mov pc, lr
140;
141; CHECK-T-LABEL: sat1_base_32bit:
142; CHECK-T:       @ %bb.0: @ %entry
143; CHECK-T-NEXT:    asrs r1, r0, #31
144; CHECK-T-NEXT:    orrs r0, r1
145; CHECK-T-NEXT:    bx lr
146;
147; CHECK-T2-LABEL: sat1_base_32bit:
148; CHECK-T2:       @ %bb.0: @ %entry
149; CHECK-T2-NEXT:    orr.w r0, r0, r0, asr #31
150; CHECK-T2-NEXT:    bx lr
151entry:
152  %cmpLow = icmp slt i32 %x, -1
153  %saturateLow = select i1 %cmpLow, i32 -1, i32 %x
154  ret i32 %saturateLow
155}
156
157; x < -1 ? -1 : x
158; 16-bit base test
159define i16 @sat1_base_16bit(i16 %x) #0 {
160; CHECK-ARM-LABEL: sat1_base_16bit:
161; CHECK-ARM:       @ %bb.0: @ %entry
162; CHECK-ARM-NEXT:    lsl r1, r0, #16
163; CHECK-ARM-NEXT:    asr r1, r1, #16
164; CHECK-ARM-NEXT:    cmn r1, #1
165; CHECK-ARM-NEXT:    mvnlt r0, #0
166; CHECK-ARM-NEXT:    mov pc, lr
167;
168; CHECK-T-LABEL: sat1_base_16bit:
169; CHECK-T:       @ %bb.0: @ %entry
170; CHECK-T-NEXT:    movs r1, #0
171; CHECK-T-NEXT:    mvns r1, r1
172; CHECK-T-NEXT:    lsls r2, r0, #16
173; CHECK-T-NEXT:    asrs r2, r2, #16
174; CHECK-T-NEXT:    cmp r2, r1
175; CHECK-T-NEXT:    blt .LBB5_2
176; CHECK-T-NEXT:  @ %bb.1: @ %entry
177; CHECK-T-NEXT:    movs r1, r0
178; CHECK-T-NEXT:  .LBB5_2: @ %entry
179; CHECK-T-NEXT:    movs r0, r1
180; CHECK-T-NEXT:    bx lr
181;
182; CHECK-T2-LABEL: sat1_base_16bit:
183; CHECK-T2:       @ %bb.0: @ %entry
184; CHECK-T2-NEXT:    sxth r1, r0
185; CHECK-T2-NEXT:    cmp.w r1, #-1
186; CHECK-T2-NEXT:    it lt
187; CHECK-T2-NEXT:    movlt.w r0, #-1
188; CHECK-T2-NEXT:    bx lr
189entry:
190  %cmpLow = icmp slt i16 %x, -1
191  %saturateLow = select i1 %cmpLow, i16 -1, i16 %x
192  ret i16 %saturateLow
193}
194
195; x < -1 ? -1 : x
196; 8-bit base test
197define i8 @sat1_base_8bit(i8 %x) #0 {
198; CHECK-ARM-LABEL: sat1_base_8bit:
199; CHECK-ARM:       @ %bb.0: @ %entry
200; CHECK-ARM-NEXT:    lsl r1, r0, #24
201; CHECK-ARM-NEXT:    asr r1, r1, #24
202; CHECK-ARM-NEXT:    cmn r1, #1
203; CHECK-ARM-NEXT:    mvnlt r0, #0
204; CHECK-ARM-NEXT:    mov pc, lr
205;
206; CHECK-T-LABEL: sat1_base_8bit:
207; CHECK-T:       @ %bb.0: @ %entry
208; CHECK-T-NEXT:    movs r1, #0
209; CHECK-T-NEXT:    mvns r1, r1
210; CHECK-T-NEXT:    lsls r2, r0, #24
211; CHECK-T-NEXT:    asrs r2, r2, #24
212; CHECK-T-NEXT:    cmp r2, r1
213; CHECK-T-NEXT:    blt .LBB6_2
214; CHECK-T-NEXT:  @ %bb.1: @ %entry
215; CHECK-T-NEXT:    movs r1, r0
216; CHECK-T-NEXT:  .LBB6_2: @ %entry
217; CHECK-T-NEXT:    movs r0, r1
218; CHECK-T-NEXT:    bx lr
219;
220; CHECK-T2-LABEL: sat1_base_8bit:
221; CHECK-T2:       @ %bb.0: @ %entry
222; CHECK-T2-NEXT:    sxtb r1, r0
223; CHECK-T2-NEXT:    cmp.w r1, #-1
224; CHECK-T2-NEXT:    it lt
225; CHECK-T2-NEXT:    movlt.w r0, #-1
226; CHECK-T2-NEXT:    bx lr
227entry:
228  %cmpLow = icmp slt i8 %x, -1
229  %saturateLow = select i1 %cmpLow, i8 -1, i8 %x
230  ret i8 %saturateLow
231}
232
233; Test where the conditional is formed in a different way
234
235; x > -1 ? x : -1
236define i32 @sat1_lower_1(i32 %x) #0 {
237; CHECK-ARM-LABEL: sat1_lower_1:
238; CHECK-ARM:       @ %bb.0: @ %entry
239; CHECK-ARM-NEXT:    orr r0, r0, r0, asr #31
240; CHECK-ARM-NEXT:    mov pc, lr
241;
242; CHECK-T-LABEL: sat1_lower_1:
243; CHECK-T:       @ %bb.0: @ %entry
244; CHECK-T-NEXT:    asrs r1, r0, #31
245; CHECK-T-NEXT:    orrs r0, r1
246; CHECK-T-NEXT:    bx lr
247;
248; CHECK-T2-LABEL: sat1_lower_1:
249; CHECK-T2:       @ %bb.0: @ %entry
250; CHECK-T2-NEXT:    orr.w r0, r0, r0, asr #31
251; CHECK-T2-NEXT:    bx lr
252entry:
253  %cmpGt = icmp sgt i32 %x, -1
254  %saturateLow = select i1 %cmpGt, i32 %x, i32 -1
255  ret i32 %saturateLow
256}
257
258; The following tests for patterns that should not transform into bitops
259; but that are similar enough that could confuse the selector.
260
261; x < 0 ? 0 : y where x and y does not properly match
262define i32 @no_sat0_incorrect_variable(i32 %x, i32 %y) #0 {
263; CHECK-ARM-LABEL: no_sat0_incorrect_variable:
264; CHECK-ARM:       @ %bb.0: @ %entry
265; CHECK-ARM-NEXT:    cmp r0, #0
266; CHECK-ARM-NEXT:    movmi r1, #0
267; CHECK-ARM-NEXT:    mov r0, r1
268; CHECK-ARM-NEXT:    mov pc, lr
269;
270; CHECK-T-LABEL: no_sat0_incorrect_variable:
271; CHECK-T:       @ %bb.0: @ %entry
272; CHECK-T-NEXT:    cmp r0, #0
273; CHECK-T-NEXT:    bpl .LBB8_2
274; CHECK-T-NEXT:  @ %bb.1:
275; CHECK-T-NEXT:    movs r1, #0
276; CHECK-T-NEXT:  .LBB8_2: @ %entry
277; CHECK-T-NEXT:    movs r0, r1
278; CHECK-T-NEXT:    bx lr
279;
280; CHECK-T2-LABEL: no_sat0_incorrect_variable:
281; CHECK-T2:       @ %bb.0: @ %entry
282; CHECK-T2-NEXT:    cmp r0, #0
283; CHECK-T2-NEXT:    it mi
284; CHECK-T2-NEXT:    movmi r1, #0
285; CHECK-T2-NEXT:    mov r0, r1
286; CHECK-T2-NEXT:    bx lr
287entry:
288  %cmpLow = icmp slt i32 %x, 0
289  %saturateLow = select i1 %cmpLow, i32 0, i32 %y
290  ret i32 %saturateLow
291}
292
293; x < 0 ? -1 : x
294define i32 @no_sat0_incorrect_constant(i32 %x) {
295; CHECK-ARM-LABEL: no_sat0_incorrect_constant:
296; CHECK-ARM:       @ %bb.0: @ %entry
297; CHECK-ARM-NEXT:    cmp r0, #0
298; CHECK-ARM-NEXT:    mvnmi r0, #0
299; CHECK-ARM-NEXT:    mov pc, lr
300;
301; CHECK-T-LABEL: no_sat0_incorrect_constant:
302; CHECK-T:       @ %bb.0: @ %entry
303; CHECK-T-NEXT:    cmp r0, #0
304; CHECK-T-NEXT:    bpl .LBB9_2
305; CHECK-T-NEXT:  @ %bb.1:
306; CHECK-T-NEXT:    movs r0, #0
307; CHECK-T-NEXT:    mvns r0, r0
308; CHECK-T-NEXT:  .LBB9_2: @ %entry
309; CHECK-T-NEXT:    bx lr
310;
311; CHECK-T2-LABEL: no_sat0_incorrect_constant:
312; CHECK-T2:       @ %bb.0: @ %entry
313; CHECK-T2-NEXT:    cmp r0, #0
314; CHECK-T2-NEXT:    it mi
315; CHECK-T2-NEXT:    movmi.w r0, #-1
316; CHECK-T2-NEXT:    bx lr
317entry:
318  %cmpLow = icmp slt i32 %x, 0
319  %saturateLow = select i1 %cmpLow, i32 -1, i32 %x
320  ret i32 %saturateLow
321}
322