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