• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 == x
8; Should be transformed into:
9;   x u<= C
10; Iff: isPowerOf2(C + 1)
11; C can be 0 and -1.
12
13; ============================================================================ ;
14; Basic positive tests
15; ============================================================================ ;
16
17define i1 @p0(i8 %x) {
18; CHECK-LABEL: @p0(
19; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i8 [[X:%.*]], 4
20; CHECK-NEXT:    ret i1 [[TMP1]]
21;
22  %tmp0 = and i8 %x, 3
23  %ret = icmp eq i8 %tmp0, %x
24  ret i1 %ret
25}
26
27define i1 @pv(i8 %x, i8 %y) {
28; CHECK-LABEL: @pv(
29; CHECK-NEXT:    [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]]
30; CHECK-NEXT:    [[TMP1:%.*]] = icmp uge i8 [[TMP0]], [[X:%.*]]
31; CHECK-NEXT:    ret i1 [[TMP1]]
32;
33  %tmp0 = lshr i8 -1, %y
34  %tmp1 = and i8 %tmp0, %x
35  %ret = icmp eq i8 %tmp1, %x
36  ret i1 %ret
37}
38
39; ============================================================================ ;
40; Vector tests
41; ============================================================================ ;
42
43define <2 x i1> @p1_vec_splat(<2 x i8> %x) {
44; CHECK-LABEL: @p1_vec_splat(
45; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult <2 x i8> [[X:%.*]], <i8 4, i8 4>
46; CHECK-NEXT:    ret <2 x i1> [[TMP1]]
47;
48  %tmp0 = and <2 x i8> %x, <i8 3, i8 3>
49  %ret = icmp eq <2 x i8> %tmp0, %x
50  ret <2 x i1> %ret
51}
52
53define <2 x i1> @p2_vec_nonsplat(<2 x i8> %x) {
54; CHECK-LABEL: @p2_vec_nonsplat(
55; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult <2 x i8> [[X:%.*]], <i8 4, i8 16>
56; CHECK-NEXT:    ret <2 x i1> [[TMP1]]
57;
58  %tmp0 = and <2 x i8> %x, <i8 3, i8 15> ; doesn't have to be splat.
59  %ret = icmp eq <2 x i8> %tmp0, %x
60  ret <2 x i1> %ret
61}
62
63define <2 x i1> @p2_vec_nonsplat_edgecase0(<2 x i8> %x) {
64; CHECK-LABEL: @p2_vec_nonsplat_edgecase0(
65; CHECK-NEXT:    [[TMP0:%.*]] = and <2 x i8> [[X:%.*]], <i8 3, i8 0>
66; CHECK-NEXT:    [[RET:%.*]] = icmp eq <2 x i8> [[TMP0]], [[X]]
67; CHECK-NEXT:    ret <2 x i1> [[RET]]
68;
69  %tmp0 = and <2 x i8> %x, <i8 3, i8 0>
70  %ret = icmp eq <2 x i8> %tmp0, %x
71  ret <2 x i1> %ret
72}
73define <2 x i1> @p2_vec_nonsplat_edgecase1(<2 x i8> %x) {
74; CHECK-LABEL: @p2_vec_nonsplat_edgecase1(
75; CHECK-NEXT:    [[TMP1:%.*]] = icmp ule <2 x i8> [[X:%.*]], <i8 3, i8 -1>
76; CHECK-NEXT:    ret <2 x i1> [[TMP1]]
77;
78  %tmp0 = and <2 x i8> %x, <i8 3, i8 -1>
79  %ret = icmp eq <2 x i8> %tmp0, %x
80  ret <2 x i1> %ret
81}
82
83define <3 x i1> @p3_vec_splat_undef(<3 x i8> %x) {
84; CHECK-LABEL: @p3_vec_splat_undef(
85; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult <3 x i8> [[X:%.*]], <i8 4, i8 4, i8 4>
86; CHECK-NEXT:    ret <3 x i1> [[TMP1]]
87;
88  %tmp0 = and <3 x i8> %x, <i8 3, i8 undef, i8 3>
89  %ret = icmp eq <3 x i8> %tmp0, %x
90  ret <3 x i1> %ret
91}
92
93; ============================================================================ ;
94; Commutativity tests.
95; ============================================================================ ;
96
97declare i8 @gen8()
98
99define i1 @c0() {
100; CHECK-LABEL: @c0(
101; CHECK-NEXT:    [[X:%.*]] = call i8 @gen8()
102; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i8 [[X]], 4
103; CHECK-NEXT:    ret i1 [[TMP1]]
104;
105  %x = call i8 @gen8()
106  %tmp0 = and i8 %x, 3
107  %ret = icmp eq i8 %x, %tmp0 ; swapped order
108  ret i1 %ret
109}
110
111; ============================================================================ ;
112; Commutativity tests with variable
113; ============================================================================ ;
114
115define i1 @cv0(i8 %y) {
116; CHECK-LABEL: @cv0(
117; CHECK-NEXT:    [[X:%.*]] = call i8 @gen8()
118; CHECK-NEXT:    [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]]
119; CHECK-NEXT:    [[TMP1:%.*]] = icmp ule i8 [[X]], [[TMP0]]
120; CHECK-NEXT:    ret i1 [[TMP1]]
121;
122  %x = call i8 @gen8()
123  %tmp0 = lshr i8 -1, %y
124  %tmp1 = and i8 %x, %tmp0 ; swapped order
125  %ret = icmp eq i8 %tmp1, %x
126  ret i1 %ret
127}
128
129define i1 @cv1(i8 %y) {
130; CHECK-LABEL: @cv1(
131; CHECK-NEXT:    [[X:%.*]] = call i8 @gen8()
132; CHECK-NEXT:    [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]]
133; CHECK-NEXT:    [[TMP1:%.*]] = icmp ule i8 [[X]], [[TMP0]]
134; CHECK-NEXT:    ret i1 [[TMP1]]
135;
136  %x = call i8 @gen8()
137  %tmp0 = lshr i8 -1, %y
138  %tmp1 = and i8 %tmp0, %x
139  %ret = icmp eq i8 %x, %tmp1 ; swapped order
140  ret i1 %ret
141}
142
143define i1 @cv2(i8 %y) {
144; CHECK-LABEL: @cv2(
145; CHECK-NEXT:    [[X:%.*]] = call i8 @gen8()
146; CHECK-NEXT:    [[TMP0:%.*]] = lshr i8 -1, [[Y:%.*]]
147; CHECK-NEXT:    [[TMP1:%.*]] = icmp ule i8 [[X]], [[TMP0]]
148; CHECK-NEXT:    ret i1 [[TMP1]]
149;
150  %x = call i8 @gen8()
151  %tmp0 = lshr i8 -1, %y
152  %tmp1 = and i8 %x, %tmp0 ; swapped order
153  %ret = icmp eq i8 %x, %tmp1 ; swapped order
154  ret i1 %ret
155}
156
157; ============================================================================ ;
158; One-use tests. We don't care about multi-uses here.
159; ============================================================================ ;
160
161declare void @use8(i8)
162
163define i1 @oneuse0(i8 %x) {
164; CHECK-LABEL: @oneuse0(
165; CHECK-NEXT:    [[TMP0:%.*]] = and i8 [[X:%.*]], 3
166; CHECK-NEXT:    call void @use8(i8 [[TMP0]])
167; CHECK-NEXT:    [[TMP1:%.*]] = icmp ult i8 [[X]], 4
168; CHECK-NEXT:    ret i1 [[TMP1]]
169;
170  %tmp0 = and i8 %x, 3
171  call void @use8(i8 %tmp0)
172  %ret = icmp eq i8 %tmp0, %x
173  ret i1 %ret
174}
175
176; ============================================================================ ;
177; Negative tests
178; ============================================================================ ;
179
180define i1 @n0(i8 %x) {
181; CHECK-LABEL: @n0(
182; CHECK-NEXT:    [[TMP0:%.*]] = and i8 [[X:%.*]], 4
183; CHECK-NEXT:    [[RET:%.*]] = icmp eq i8 [[TMP0]], [[X]]
184; CHECK-NEXT:    ret i1 [[RET]]
185;
186  %tmp0 = and i8 %x, 4 ; power-of-two, but invalid.
187  %ret = icmp eq i8 %tmp0, %x
188  ret i1 %ret
189}
190
191define i1 @n1(i8 %x, i8 %y, i8 %notx) {
192; CHECK-LABEL: @n1(
193; CHECK-NEXT:    [[TMP0:%.*]] = and i8 [[X:%.*]], 3
194; CHECK-NEXT:    [[RET:%.*]] = icmp eq i8 [[TMP0]], [[NOTX:%.*]]
195; CHECK-NEXT:    ret i1 [[RET]]
196;
197  %tmp0 = and i8 %x, 3
198  %ret = icmp eq i8 %tmp0, %notx ; not %x
199  ret i1 %ret
200}
201
202define <2 x i1> @n2(<2 x i8> %x) {
203; CHECK-LABEL: @n2(
204; CHECK-NEXT:    [[TMP0:%.*]] = and <2 x i8> [[X:%.*]], <i8 3, i8 16>
205; CHECK-NEXT:    [[RET:%.*]] = icmp eq <2 x i8> [[TMP0]], [[X]]
206; CHECK-NEXT:    ret <2 x i1> [[RET]]
207;
208  %tmp0 = and <2 x i8> %x, <i8 3, i8 16> ; only the first one is valid.
209  %ret = icmp eq <2 x i8> %tmp0, %x
210  ret <2 x i1> %ret
211}
212