1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -passes=instcombine -S %s | FileCheck %s
4 ; Check that we simplify llvm.umul.with.overflow, if the overflow check is
5 ; weakened by or (icmp ne %res, 0) %overflow. This is generated by code using
6 ; __builtin_mul_overflow with negative integer constants, e.g.
8 ; bool test(unsigned long long v, unsigned long long *res) {
9 ; return __builtin_mul_overflow(v, -4775807LL, res);
12 declare { i64, i1 } @llvm.umul.with.overflow.i64(i64, i64) #0
14 define i1 @test1(i64 %a, i64 %b, ptr %ptr) {
15 ; CHECK-LABEL: @test1(
16 ; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[A:%.*]], [[B:%.*]]
17 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0
18 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0
19 ; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]]
20 ; CHECK-NEXT: store i64 [[MUL]], ptr [[PTR:%.*]], align 8
21 ; CHECK-NEXT: ret i1 [[OVERFLOW_1]]
24 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b)
25 %overflow = extractvalue { i64, i1 } %res, 1
26 %mul = extractvalue { i64, i1 } %res, 0
27 %cmp = icmp ne i64 %mul, 0
28 %overflow.1 = or i1 %overflow, %cmp
29 store i64 %mul, ptr %ptr, align 8
33 define i1 @test1_logical(i64 %a, i64 %b, ptr %ptr) {
34 ; CHECK-LABEL: @test1_logical(
35 ; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[A:%.*]], [[B:%.*]]
36 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0
37 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0
38 ; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]]
39 ; CHECK-NEXT: store i64 [[MUL]], ptr [[PTR:%.*]], align 8
40 ; CHECK-NEXT: ret i1 [[OVERFLOW_1]]
43 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b)
44 %overflow = extractvalue { i64, i1 } %res, 1
45 %mul = extractvalue { i64, i1 } %res, 0
46 %cmp = icmp ne i64 %mul, 0
47 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp
48 store i64 %mul, ptr %ptr, align 8
52 define i1 @test1_or_ops_swapped(i64 %a, i64 %b, ptr %ptr) {
53 ; CHECK-LABEL: @test1_or_ops_swapped(
54 ; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[A:%.*]], [[B:%.*]]
55 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0
56 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0
57 ; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]]
58 ; CHECK-NEXT: store i64 [[MUL]], ptr [[PTR:%.*]], align 8
59 ; CHECK-NEXT: ret i1 [[OVERFLOW_1]]
63 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b)
64 %overflow = extractvalue { i64, i1 } %res, 1
65 %mul = extractvalue { i64, i1 } %res, 0
66 %cmp = icmp ne i64 %mul, 0
67 %overflow.1 = or i1 %cmp, %overflow
68 store i64 %mul, ptr %ptr, align 8
72 define i1 @test1_or_ops_swapped_logical(i64 %a, i64 %b, ptr %ptr) {
73 ; CHECK-LABEL: @test1_or_ops_swapped_logical(
74 ; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[A:%.*]], [[B:%.*]]
75 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0
76 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0
77 ; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]]
78 ; CHECK-NEXT: store i64 [[MUL]], ptr [[PTR:%.*]], align 8
79 ; CHECK-NEXT: ret i1 [[OVERFLOW_1]]
83 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b)
84 %overflow = extractvalue { i64, i1 } %res, 1
85 %mul = extractvalue { i64, i1 } %res, 0
86 %cmp = icmp ne i64 %mul, 0
87 %overflow.1 = select i1 %cmp, i1 true, i1 %overflow
88 store i64 %mul, ptr %ptr, align 8
92 define i1 @test2(i64 %a, i64 %b, ptr %ptr) {
93 ; CHECK-LABEL: @test2(
94 ; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[A:%.*]], [[B:%.*]]
95 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0
96 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0
97 ; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]]
98 ; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]]
99 ; CHECK-NEXT: store i64 [[NEG]], ptr [[PTR:%.*]], align 8
100 ; CHECK-NEXT: ret i1 [[OVERFLOW_1]]
103 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b)
104 %overflow = extractvalue { i64, i1 } %res, 1
105 %mul = extractvalue { i64, i1 } %res, 0
106 %cmp = icmp ne i64 %mul, 0
107 %overflow.1 = or i1 %overflow, %cmp
108 %neg = sub i64 0, %mul
109 store i64 %neg, ptr %ptr, align 8
113 define i1 @test2_logical(i64 %a, i64 %b, ptr %ptr) {
114 ; CHECK-LABEL: @test2_logical(
115 ; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[A:%.*]], [[B:%.*]]
116 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0
117 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0
118 ; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]]
119 ; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]]
120 ; CHECK-NEXT: store i64 [[NEG]], ptr [[PTR:%.*]], align 8
121 ; CHECK-NEXT: ret i1 [[OVERFLOW_1]]
124 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b)
125 %overflow = extractvalue { i64, i1 } %res, 1
126 %mul = extractvalue { i64, i1 } %res, 0
127 %cmp = icmp ne i64 %mul, 0
128 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp
129 %neg = sub i64 0, %mul
130 store i64 %neg, ptr %ptr, align 8
134 declare void @use(i1)
136 define i1 @test3_multiple_overflow_users(i64 %a, i64 %b, ptr %ptr) {
137 ; CHECK-LABEL: @test3_multiple_overflow_users(
138 ; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]])
139 ; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[RES]], 1
140 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0
141 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0
142 ; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]]
143 ; CHECK-NEXT: call void @use(i1 [[OVERFLOW]])
144 ; CHECK-NEXT: ret i1 [[OVERFLOW_1]]
146 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b)
147 %overflow = extractvalue { i64, i1 } %res, 1
148 %mul = extractvalue { i64, i1 } %res, 0
149 %cmp = icmp ne i64 %mul, 0
150 %overflow.1 = or i1 %overflow, %cmp
151 call void @use(i1 %overflow)
155 define i1 @test3_multiple_overflow_users_logical(i64 %a, i64 %b, ptr %ptr) {
156 ; CHECK-LABEL: @test3_multiple_overflow_users_logical(
157 ; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]])
158 ; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[RES]], 1
159 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0
160 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0
161 ; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]]
162 ; CHECK-NEXT: call void @use(i1 [[OVERFLOW]])
163 ; CHECK-NEXT: ret i1 [[OVERFLOW_1]]
165 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b)
166 %overflow = extractvalue { i64, i1 } %res, 1
167 %mul = extractvalue { i64, i1 } %res, 0
168 %cmp = icmp ne i64 %mul, 0
169 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp
170 call void @use(i1 %overflow)
174 ; Do not simplify if %overflow and %mul have multiple uses.
175 define i1 @test3_multiple_overflow_and_mul_users(i64 %a, i64 %b, ptr %ptr) {
176 ; CHECK-LABEL: @test3_multiple_overflow_and_mul_users(
177 ; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]])
178 ; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[RES]], 1
179 ; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0
180 ; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[MUL]], 0
181 ; CHECK-NEXT: [[OVERFLOW_1:%.*]] = or i1 [[OVERFLOW]], [[CMP]]
182 ; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]]
183 ; CHECK-NEXT: store i64 [[NEG]], ptr [[PTR:%.*]], align 8
184 ; CHECK-NEXT: call void @use(i1 [[OVERFLOW]])
185 ; CHECK-NEXT: ret i1 [[OVERFLOW_1]]
187 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b)
188 %overflow = extractvalue { i64, i1 } %res, 1
189 %mul = extractvalue { i64, i1 } %res, 0
190 %cmp = icmp ne i64 %mul, 0
191 %overflow.1 = or i1 %overflow, %cmp
192 %neg = sub i64 0, %mul
193 store i64 %neg, ptr %ptr, align 8
194 call void @use(i1 %overflow)
198 define i1 @test3_multiple_overflow_and_mul_users_logical(i64 %a, i64 %b, ptr %ptr) {
199 ; CHECK-LABEL: @test3_multiple_overflow_and_mul_users_logical(
200 ; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]])
201 ; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[RES]], 1
202 ; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0
203 ; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[MUL]], 0
204 ; CHECK-NEXT: [[OVERFLOW_1:%.*]] = or i1 [[OVERFLOW]], [[CMP]]
205 ; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]]
206 ; CHECK-NEXT: store i64 [[NEG]], ptr [[PTR:%.*]], align 8
207 ; CHECK-NEXT: call void @use(i1 [[OVERFLOW]])
208 ; CHECK-NEXT: ret i1 [[OVERFLOW_1]]
210 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b)
211 %overflow = extractvalue { i64, i1 } %res, 1
212 %mul = extractvalue { i64, i1 } %res, 0
213 %cmp = icmp ne i64 %mul, 0
214 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp
215 %neg = sub i64 0, %mul
216 store i64 %neg, ptr %ptr, align 8
217 call void @use(i1 %overflow)
222 declare void @use.2({ i64, i1 })
223 define i1 @test3_multiple_res_users(i64 %a, i64 %b, ptr %ptr) {
224 ; CHECK-LABEL: @test3_multiple_res_users(
225 ; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]])
226 ; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0
227 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0
228 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0
229 ; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]]
230 ; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]]
231 ; CHECK-NEXT: store i64 [[NEG]], ptr [[PTR:%.*]], align 8
232 ; CHECK-NEXT: call void @use.2({ i64, i1 } [[RES]])
233 ; CHECK-NEXT: ret i1 [[OVERFLOW_1]]
235 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b)
236 %overflow = extractvalue { i64, i1 } %res, 1
237 %mul = extractvalue { i64, i1 } %res, 0
238 %cmp = icmp ne i64 %mul, 0
239 %overflow.1 = or i1 %overflow, %cmp
240 %neg = sub i64 0, %mul
241 store i64 %neg, ptr %ptr, align 8
242 call void @use.2({ i64, i1 } %res)
246 define i1 @test3_multiple_res_users_logical(i64 %a, i64 %b, ptr %ptr) {
247 ; CHECK-LABEL: @test3_multiple_res_users_logical(
248 ; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]])
249 ; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0
250 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0
251 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0
252 ; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]]
253 ; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]]
254 ; CHECK-NEXT: store i64 [[NEG]], ptr [[PTR:%.*]], align 8
255 ; CHECK-NEXT: call void @use.2({ i64, i1 } [[RES]])
256 ; CHECK-NEXT: ret i1 [[OVERFLOW_1]]
258 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b)
259 %overflow = extractvalue { i64, i1 } %res, 1
260 %mul = extractvalue { i64, i1 } %res, 0
261 %cmp = icmp ne i64 %mul, 0
262 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp
263 %neg = sub i64 0, %mul
264 store i64 %neg, ptr %ptr, align 8
265 call void @use.2({ i64, i1 } %res)
269 declare void @use.3(i64)
271 ; Simplify if %mul has multiple uses.
272 define i1 @test3_multiple_mul_users(i64 %a, i64 %b, ptr %ptr) {
273 ; CHECK-LABEL: @test3_multiple_mul_users(
274 ; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[A:%.*]], [[B:%.*]]
275 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0
276 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0
277 ; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]]
278 ; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]]
279 ; CHECK-NEXT: store i64 [[NEG]], ptr [[PTR:%.*]], align 8
280 ; CHECK-NEXT: call void @use.3(i64 [[MUL]])
281 ; CHECK-NEXT: ret i1 [[OVERFLOW_1]]
284 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b)
285 %overflow = extractvalue { i64, i1 } %res, 1
286 %mul = extractvalue { i64, i1 } %res, 0
287 %cmp = icmp ne i64 %mul, 0
288 %overflow.1 = or i1 %overflow, %cmp
289 %neg = sub i64 0, %mul
290 store i64 %neg, ptr %ptr, align 8
291 call void @use.3(i64 %mul)
295 define i1 @test3_multiple_mul_users_logical(i64 %a, i64 %b, ptr %ptr) {
296 ; CHECK-LABEL: @test3_multiple_mul_users_logical(
297 ; CHECK-NEXT: [[MUL:%.*]] = mul i64 [[A:%.*]], [[B:%.*]]
298 ; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i64 [[A]], 0
299 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[B]], 0
300 ; CHECK-NEXT: [[OVERFLOW_1:%.*]] = and i1 [[TMP1]], [[TMP2]]
301 ; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]]
302 ; CHECK-NEXT: store i64 [[NEG]], ptr [[PTR:%.*]], align 8
303 ; CHECK-NEXT: call void @use.3(i64 [[MUL]])
304 ; CHECK-NEXT: ret i1 [[OVERFLOW_1]]
307 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b)
308 %overflow = extractvalue { i64, i1 } %res, 1
309 %mul = extractvalue { i64, i1 } %res, 0
310 %cmp = icmp ne i64 %mul, 0
311 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp
312 %neg = sub i64 0, %mul
313 store i64 %neg, ptr %ptr, align 8
314 call void @use.3(i64 %mul)
320 define i1 @test4_no_icmp_ne(i64 %a, i64 %b, ptr %ptr) {
321 ; CHECK-LABEL: @test4_no_icmp_ne(
322 ; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]])
323 ; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[RES]], 1
324 ; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0
325 ; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[MUL]], 0
326 ; CHECK-NEXT: [[OVERFLOW_1:%.*]] = or i1 [[OVERFLOW]], [[CMP]]
327 ; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]]
328 ; CHECK-NEXT: store i64 [[NEG]], ptr [[PTR:%.*]], align 8
329 ; CHECK-NEXT: ret i1 [[OVERFLOW_1]]
331 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b)
332 %overflow = extractvalue { i64, i1 } %res, 1
333 %mul = extractvalue { i64, i1 } %res, 0
334 %cmp = icmp sgt i64 %mul, 0
335 %overflow.1 = or i1 %overflow, %cmp
336 %neg = sub i64 0, %mul
337 store i64 %neg, ptr %ptr, align 8
341 define i1 @test4_no_icmp_ne_logical(i64 %a, i64 %b, ptr %ptr) {
342 ; CHECK-LABEL: @test4_no_icmp_ne_logical(
343 ; CHECK-NEXT: [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 [[B:%.*]])
344 ; CHECK-NEXT: [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[RES]], 1
345 ; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0
346 ; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[MUL]], 0
347 ; CHECK-NEXT: [[OVERFLOW_1:%.*]] = or i1 [[OVERFLOW]], [[CMP]]
348 ; CHECK-NEXT: [[NEG:%.*]] = sub i64 0, [[MUL]]
349 ; CHECK-NEXT: store i64 [[NEG]], ptr [[PTR:%.*]], align 8
350 ; CHECK-NEXT: ret i1 [[OVERFLOW_1]]
352 %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b)
353 %overflow = extractvalue { i64, i1 } %res, 1
354 %mul = extractvalue { i64, i1 } %res, 0
355 %cmp = icmp sgt i64 %mul, 0
356 %overflow.1 = select i1 %overflow, i1 true, i1 %cmp
357 %neg = sub i64 0, %mul
358 store i64 %neg, ptr %ptr, align 8
362 attributes #0 = { nounwind readnone speculatable willreturn }