1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -instcombine -S | FileCheck %s
3
4; https://bugs.llvm.org/show_bug.cgi?id=38123
5
6; Pattern:
7;   x & C s>= x
8; Should be transformed into:
9;   x s<= C
10; Iff: isPowerOf2(C + 1)
11
12; ============================================================================ ;
13; Basic positive tests
14; ============================================================================ ;
15
16define i1 @p0(i8 %x) {
17; CHECK-LABEL: @p0(
18; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i8 [[X:%.*]], 4
19; CHECK-NEXT:    ret i1 [[TMP1]]
20;
21  %tmp0 = and i8 %x, 3
22  %ret = icmp sge i8 %tmp0, %x
23  ret i1 %ret
24}
25
26; ============================================================================ ;
27; Vector tests
28; ============================================================================ ;
29
30define <2 x i1> @p1_vec_splat(<2 x i8> %x) {
31; CHECK-LABEL: @p1_vec_splat(
32; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt <2 x i8> [[X:%.*]], <i8 4, i8 4>
33; CHECK-NEXT:    ret <2 x i1> [[TMP1]]
34;
35  %tmp0 = and <2 x i8> %x, <i8 3, i8 3>
36  %ret = icmp sge <2 x i8> %tmp0, %x
37  ret <2 x i1> %ret
38}
39
40define <2 x i1> @p2_vec_nonsplat(<2 x i8> %x) {
41; CHECK-LABEL: @p2_vec_nonsplat(
42; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt <2 x i8> [[X:%.*]], <i8 4, i8 16>
43; CHECK-NEXT:    ret <2 x i1> [[TMP1]]
44;
45  %tmp0 = and <2 x i8> %x, <i8 3, i8 15> ; doesn't have to be splat.
46  %ret = icmp sge <2 x i8> %tmp0, %x
47  ret <2 x i1> %ret
48}
49
50define <3 x i1> @p3_vec_splat_undef(<3 x i8> %x) {
51; CHECK-LABEL: @p3_vec_splat_undef(
52; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt <3 x i8> [[X:%.*]], <i8 4, i8 undef, i8 4>
53; CHECK-NEXT:    ret <3 x i1> [[TMP1]]
54;
55  %tmp0 = and <3 x i8> %x, <i8 3, i8 undef, i8 3>
56  %ret = icmp sge <3 x i8> %tmp0, %x
57  ret <3 x i1> %ret
58}
59
60; ============================================================================ ;
61; One-use tests. We don't care about multi-uses here.
62; ============================================================================ ;
63
64declare void @use8(i8)
65
66define i1 @oneuse0(i8 %x) {
67; CHECK-LABEL: @oneuse0(
68; CHECK-NEXT:    [[TMP0:%.*]] = and i8 [[X:%.*]], 3
69; CHECK-NEXT:    call void @use8(i8 [[TMP0]])
70; CHECK-NEXT:    [[TMP1:%.*]] = icmp slt i8 [[X]], 4
71; CHECK-NEXT:    ret i1 [[TMP1]]
72;
73  %tmp0 = and i8 %x, 3
74  call void @use8(i8 %tmp0)
75  %ret = icmp sge i8 %tmp0, %x
76  ret i1 %ret
77}
78
79; ============================================================================ ;
80; Negative tests
81; ============================================================================ ;
82
83; ============================================================================ ;
84; Commutativity tests.
85; ============================================================================ ;
86
87declare i8 @gen8()
88
89define i1 @c0() {
90; CHECK-LABEL: @c0(
91; CHECK-NEXT:    [[X:%.*]] = call i8 @gen8()
92; CHECK-NEXT:    [[TMP0:%.*]] = and i8 [[X]], 3
93; CHECK-NEXT:    [[RET:%.*]] = icmp sge i8 [[X]], [[TMP0]]
94; CHECK-NEXT:    ret i1 [[RET]]
95;
96  %x = call i8 @gen8()
97  %tmp0 = and i8 %x, 3
98  %ret = icmp sge i8 %x, %tmp0 ; swapped order
99  ret i1 %ret
100}
101
102; ============================================================================ ;
103; Commutativity tests with variable
104; ============================================================================ ;
105
106; Ok, this one should fold. We only testing commutativity of 'and'.
107define i1 @cv0(i8 %y) {
108; CHECK-LABEL: @cv0(
109; CHECK-NEXT:    [[X:%.*]] = call i8 @gen8()
110; CHECK-NEXT:    [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]]
111; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[X]], [[TMP0]]
112; CHECK-NEXT:    [[RET:%.*]] = icmp sge i8 [[TMP1]], [[X]]
113; CHECK-NEXT:    ret i1 [[RET]]
114;
115  %x = call i8 @gen8()
116  %tmp0 = lshr i8 -1, %y
117  %tmp1 = and i8 %x, %tmp0 ; swapped order
118  %ret = icmp sge i8 %tmp1, %x
119  ret i1 %ret
120}
121
122define i1 @cv1(i8 %y) {
123; CHECK-LABEL: @cv1(
124; CHECK-NEXT:    [[X:%.*]] = call i8 @gen8()
125; CHECK-NEXT:    [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]]
126; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[TMP0]], [[X]]
127; CHECK-NEXT:    [[RET:%.*]] = icmp sge i8 [[X]], [[TMP1]]
128; CHECK-NEXT:    ret i1 [[RET]]
129;
130  %x = call i8 @gen8()
131  %tmp0 = lshr i8 -1, %y
132  %tmp1 = and i8 %tmp0, %x
133  %ret = icmp sge i8 %x, %tmp1 ; swapped order
134  ret i1 %ret
135}
136
137define i1 @cv2(i8 %y) {
138; CHECK-LABEL: @cv2(
139; CHECK-NEXT:    [[X:%.*]] = call i8 @gen8()
140; CHECK-NEXT:    [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]]
141; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[X]], [[TMP0]]
142; CHECK-NEXT:    [[RET:%.*]] = icmp sge i8 [[X]], [[TMP1]]
143; CHECK-NEXT:    ret i1 [[RET]]
144;
145  %x = call i8 @gen8()
146  %tmp0 = lshr i8 -1, %y
147  %tmp1 = and i8 %x, %tmp0 ; swapped order
148  %ret = icmp sge i8 %x, %tmp1 ; swapped order
149  ret i1 %ret
150}
151
152; ============================================================================ ;
153; Normal negative tests
154; ============================================================================ ;
155
156define i1 @n0(i8 %x) {
157; CHECK-LABEL: @n0(
158; CHECK-NEXT:    [[TMP0:%.*]] = and i8 [[X:%.*]], 4
159; CHECK-NEXT:    [[RET:%.*]] = icmp sge i8 [[TMP0]], [[X]]
160; CHECK-NEXT:    ret i1 [[RET]]
161;
162  %tmp0 = and i8 %x, 4 ; power-of-two, but invalid.
163  %ret = icmp sge i8 %tmp0, %x
164  ret i1 %ret
165}
166
167define i1 @n1(i8 %x, i8 %y, i8 %notx) {
168; CHECK-LABEL: @n1(
169; CHECK-NEXT:    [[TMP0:%.*]] = and i8 [[X:%.*]], 3
170; CHECK-NEXT:    [[RET:%.*]] = icmp sge i8 [[TMP0]], [[NOTX:%.*]]
171; CHECK-NEXT:    ret i1 [[RET]]
172;
173  %tmp0 = and i8 %x, 3
174  %ret = icmp sge i8 %tmp0, %notx ; not %x
175  ret i1 %ret
176}
177
178define <2 x i1> @n2(<2 x i8> %x) {
179; CHECK-LABEL: @n2(
180; CHECK-NEXT:    [[TMP0:%.*]] = and <2 x i8> [[X:%.*]], <i8 3, i8 16>
181; CHECK-NEXT:    [[RET:%.*]] = icmp sge <2 x i8> [[TMP0]], [[X]]
182; CHECK-NEXT:    ret <2 x i1> [[RET]]
183;
184  %tmp0 = and <2 x i8> %x, <i8 3, i8 16> ; only the first one is valid.
185  %ret = icmp sge <2 x i8> %tmp0, %x
186  ret <2 x i1> %ret
187}
188
189; ============================================================================ ;
190; Potential miscompiles.
191; ============================================================================ ;
192
193define i1 @nv(i8 %x, i8 %y) {
194; CHECK-LABEL: @nv(
195; CHECK-NEXT:    [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]]
196; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[TMP0]], [[X:%.*]]
197; CHECK-NEXT:    [[RET:%.*]] = icmp sge i8 [[TMP1]], [[X]]
198; CHECK-NEXT:    ret i1 [[RET]]
199;
200  %tmp0 = lshr i8 -1, %y
201  %tmp1 = and i8 %tmp0, %x
202  %ret = icmp sge i8 %tmp1, %x
203  ret i1 %ret
204}
205
206define <2 x i1> @n3_vec(<2 x i8> %x) {
207; CHECK-LABEL: @n3_vec(
208; CHECK-NEXT:    [[TMP0:%.*]] = and <2 x i8> [[X:%.*]], <i8 3, i8 -1>
209; CHECK-NEXT:    [[RET:%.*]] = icmp sge <2 x i8> [[TMP0]], [[X]]
210; CHECK-NEXT:    ret <2 x i1> [[RET]]
211;
212  %tmp0 = and <2 x i8> %x, <i8 3, i8 -1>
213  %ret = icmp sge <2 x i8> %tmp0, %x
214  ret <2 x i1> %ret
215}
216
217define <3 x i1> @n4_vec(<3 x i8> %x) {
218; CHECK-LABEL: @n4_vec(
219; CHECK-NEXT:    [[TMP0:%.*]] = and <3 x i8> [[X:%.*]], <i8 3, i8 undef, i8 -1>
220; CHECK-NEXT:    [[RET:%.*]] = icmp sge <3 x i8> [[TMP0]], [[X]]
221; CHECK-NEXT:    ret <3 x i1> [[RET]]
222;
223  %tmp0 = and <3 x i8> %x, <i8 3, i8 undef, i8 -1>
224  %ret = icmp sge <3 x i8> %tmp0, %x
225  ret <3 x i1> %ret
226}
227