1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -instcombine -S | FileCheck %s
3
4target datalayout = "n32"
5
6define i1 @is_rem2_neg_i8(i8 %x) {
7; CHECK-LABEL: @is_rem2_neg_i8(
8; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[X:%.*]], -127
9; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[TMP1]], -127
10; CHECK-NEXT:    ret i1 [[R]]
11;
12  %s = srem i8 %x, 2
13  %r = icmp slt i8 %s, 0
14  ret i1 %r
15}
16
17define <2 x i1> @is_rem2_pos_v2i8(<2 x i8> %x) {
18; CHECK-LABEL: @is_rem2_pos_v2i8(
19; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], <i8 -127, i8 -127>
20; CHECK-NEXT:    [[R:%.*]] = icmp eq <2 x i8> [[TMP1]], <i8 1, i8 1>
21; CHECK-NEXT:    ret <2 x i1> [[R]]
22;
23  %s = srem <2 x i8> %x, <i8 2, i8 2>
24  %r = icmp sgt <2 x i8> %s, zeroinitializer
25  ret <2 x i1> %r
26}
27
28; i8 -97 == 159 == 0b10011111
29
30define i1 @is_rem32_pos_i8(i8 %x) {
31; CHECK-LABEL: @is_rem32_pos_i8(
32; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[X:%.*]], -97
33; CHECK-NEXT:    [[R:%.*]] = icmp sgt i8 [[TMP1]], 0
34; CHECK-NEXT:    ret i1 [[R]]
35;
36  %s = srem i8 %x, 32
37  %r = icmp sgt i8 %s, 0
38  ret i1 %r
39}
40
41; i16 -32765 == 32771 == 0b1000000000000011
42
43define i1 @is_rem4_neg_i16(i16 %x) {
44; CHECK-LABEL: @is_rem4_neg_i16(
45; CHECK-NEXT:    [[TMP1:%.*]] = and i16 [[X:%.*]], -32765
46; CHECK-NEXT:    [[R:%.*]] = icmp ugt i16 [[TMP1]], -32768
47; CHECK-NEXT:    ret i1 [[R]]
48;
49  %s = srem i16 %x, 4
50  %r = icmp slt i16 %s, 0
51  ret i1 %r
52}
53
54declare void @use(i32)
55
56; TODO: This is still worth folding because srem is difficult?
57
58define i1 @is_rem32_neg_i32_extra_use(i32 %x) {
59; CHECK-LABEL: @is_rem32_neg_i32_extra_use(
60; CHECK-NEXT:    [[S:%.*]] = srem i32 [[X:%.*]], 32
61; CHECK-NEXT:    call void @use(i32 [[S]])
62; CHECK-NEXT:    [[R:%.*]] = icmp slt i32 [[S]], 0
63; CHECK-NEXT:    ret i1 [[R]]
64;
65  %s = srem i32 %x, 32
66  call void @use(i32 %s)
67  %r = icmp slt i32 %s, 0
68  ret i1 %r
69}
70
71; Negative test - wrong compare constant
72
73define i1 @is_rem8_nonneg_i16(i16 %x) {
74; CHECK-LABEL: @is_rem8_nonneg_i16(
75; CHECK-NEXT:    [[S:%.*]] = srem i16 [[X:%.*]], 8
76; CHECK-NEXT:    [[R:%.*]] = icmp sgt i16 [[S]], -1
77; CHECK-NEXT:    ret i1 [[R]]
78;
79  %s = srem i16 %x, 8
80  %r = icmp sgt i16 %s, -1
81  ret i1 %r
82}
83
84; Negative test - wrong remainder constant
85
86define i1 @is_rem3_neg_i8(i8 %x) {
87; CHECK-LABEL: @is_rem3_neg_i8(
88; CHECK-NEXT:    [[S:%.*]] = srem i8 [[X:%.*]], 3
89; CHECK-NEXT:    [[R:%.*]] = icmp slt i8 [[S]], 0
90; CHECK-NEXT:    ret i1 [[R]]
91;
92  %s = srem i8 %x, 3
93  %r = icmp slt i8 %s, 0
94  ret i1 %r
95}
96
97; Negative test - wrong compare constant
98
99define i1 @is_rem16_something_i8(i8 %x) {
100; CHECK-LABEL: @is_rem16_something_i8(
101; CHECK-NEXT:    [[S:%.*]] = srem i8 [[X:%.*]], 16
102; CHECK-NEXT:    [[R:%.*]] = icmp slt i8 [[S]], 7
103; CHECK-NEXT:    ret i1 [[R]]
104;
105  %s = srem i8 %x, 16
106  %r = icmp slt i8 %s, 7
107  ret i1 %r
108}
109
110; PR30281 - https://llvm.org/bugs/show_bug.cgi?id=30281
111
112; All of these tests contain foldable division-by-constant instructions, but we
113; can't assert that those folds have occurred before we process the later icmp.
114
115define i32 @icmp_div(i16 %a, i16 %c) {
116; CHECK-LABEL: @icmp_div(
117; CHECK-NEXT:  entry:
118; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0
119; CHECK-NEXT:    br i1 [[TOBOOL]], label [[THEN:%.*]], label [[EXIT:%.*]]
120; CHECK:       then:
121; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i16 [[C:%.*]], 0
122; CHECK-NEXT:    [[PHITMP1:%.*]] = sext i1 [[CMP]] to i32
123; CHECK-NEXT:    br label [[EXIT]]
124; CHECK:       exit:
125; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[PHITMP1]], [[THEN]] ]
126; CHECK-NEXT:    ret i32 [[PHI]]
127;
128entry:
129  %tobool = icmp eq i16 %a, 0
130  br i1 %tobool, label %then, label %exit
131
132then:
133  %div = sdiv i16 %c, -1
134  %cmp = icmp ne i16 %div, 0
135  br label %exit
136
137exit:
138  %phi = phi i1 [ false, %entry ], [ %cmp, %then ]
139  %zext = zext i1 %phi to i32
140  %add = add nsw i32 %zext, -1
141  ret i32 %add
142}
143
144define i32 @icmp_div2(i16 %a, i16 %c) {
145; CHECK-LABEL: @icmp_div2(
146; CHECK-NEXT:  entry:
147; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0
148; CHECK-NEXT:    br i1 [[TOBOOL]], label [[THEN:%.*]], label [[EXIT:%.*]]
149; CHECK:       then:
150; CHECK-NEXT:    br label [[EXIT]]
151; CHECK:       exit:
152; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ 0, [[THEN]] ]
153; CHECK-NEXT:    ret i32 [[PHI]]
154;
155entry:
156  %tobool = icmp eq i16 %a, 0
157  br i1 %tobool, label %then, label %exit
158
159then:
160  %div = sdiv i16 %c, 0
161  %cmp = icmp ne i16 %div, 0
162  br label %exit
163
164exit:
165  %phi = phi i1 [ false, %entry ], [ %cmp, %then ]
166  %zext = zext i1 %phi to i32
167  %add = add nsw i32 %zext, -1
168  ret i32 %add
169}
170
171define i32 @icmp_div3(i16 %a, i16 %c) {
172; CHECK-LABEL: @icmp_div3(
173; CHECK-NEXT:  entry:
174; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0
175; CHECK-NEXT:    br i1 [[TOBOOL]], label [[THEN:%.*]], label [[EXIT:%.*]]
176; CHECK:       then:
177; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i16 [[C:%.*]], 0
178; CHECK-NEXT:    [[PHITMP1:%.*]] = sext i1 [[CMP]] to i32
179; CHECK-NEXT:    br label [[EXIT]]
180; CHECK:       exit:
181; CHECK-NEXT:    [[PHI:%.*]] = phi i32 [ -1, [[ENTRY:%.*]] ], [ [[PHITMP1]], [[THEN]] ]
182; CHECK-NEXT:    ret i32 [[PHI]]
183;
184entry:
185  %tobool = icmp eq i16 %a, 0
186  br i1 %tobool, label %then, label %exit
187
188then:
189  %div = sdiv i16 %c, 1
190  %cmp = icmp ne i16 %div, 0
191  br label %exit
192
193exit:
194  %phi = phi i1 [ false, %entry ], [ %cmp, %then ]
195  %zext = zext i1 %phi to i32
196  %add = add nsw i32 %zext, -1
197  ret i32 %add
198}
199
200