[DAGCombiner] Add target hook function to decide folding (mul (add x, c1), c2)
[llvm-project.git] / llvm / test / Transforms / InstCombine / umul-sign-check.ll
blob8fa659396f2e1fc788aa7bd511ab9205145748dd
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -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);
10 ;   }
12 declare { i64, i1 } @llvm.umul.with.overflow.i64(i64, i64) #0
14 define i1 @test1(i64 %a, i64 %b, i64* %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]], i64* [[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, i64* %ptr, align 8
30   ret i1 %overflow.1
33 define i1 @test1_logical(i64 %a, i64 %b, i64* %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]], i64* [[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, i64* %ptr, align 8
49   ret i1 %overflow.1
52 define i1 @test1_or_ops_swapped(i64 %a, i64 %b, i64* %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]], i64* [[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, i64* %ptr, align 8
69   ret i1 %overflow.1
72 define i1 @test1_or_ops_swapped_logical(i64 %a, i64 %b, i64* %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]], i64* [[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, i64* %ptr, align 8
89   ret i1 %overflow.1
92 define i1 @test2(i64 %a, i64 %b, i64* %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]], i64* [[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, i64* %ptr, align 8
110   ret i1 %overflow.1
113 define i1 @test2_logical(i64 %a, i64 %b, i64* %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]], i64* [[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, i64* %ptr, align 8
131   ret i1 %overflow.1
134 declare void @use(i1)
136 define i1 @test3_multiple_overflow_users(i64 %a, i64 %b, i64* %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)
152   ret i1 %overflow.1
155 define i1 @test3_multiple_overflow_users_logical(i64 %a, i64 %b, i64* %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)
171   ret i1 %overflow.1
174 ; Do not simplify if %overflow and %mul have multiple uses.
175 define i1 @test3_multiple_overflow_and_mul_users(i64 %a, i64 %b, i64* %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]], i64* [[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, i64* %ptr, align 8
194   call void @use(i1 %overflow)
195   ret i1 %overflow.1
198 define i1 @test3_multiple_overflow_and_mul_users_logical(i64 %a, i64 %b, i64* %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]], i64* [[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, i64* %ptr, align 8
217   call void @use(i1 %overflow)
218   ret i1 %overflow.1
222 declare void @use.2({ i64, i1 })
223 define i1 @test3_multiple_res_users(i64 %a, i64 %b, i64* %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]], i64* [[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, i64* %ptr, align 8
242   call void @use.2({ i64, i1 } %res)
243   ret i1 %overflow.1
246 define i1 @test3_multiple_res_users_logical(i64 %a, i64 %b, i64* %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]], i64* [[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, i64* %ptr, align 8
265   call void @use.2({ i64, i1 } %res)
266   ret i1 %overflow.1
269 declare void @use.3(i64)
271 ; Simplify if %mul has multiple uses.
272 define i1 @test3_multiple_mul_users(i64 %a, i64 %b, i64* %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]], i64* [[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, i64* %ptr, align 8
291   call void @use.3(i64 %mul)
292   ret i1 %overflow.1
295 define i1 @test3_multiple_mul_users_logical(i64 %a, i64 %b, i64* %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]], i64* [[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, i64* %ptr, align 8
314   call void @use.3(i64 %mul)
315   ret i1 %overflow.1
320 define i1 @test4_no_icmp_ne(i64 %a, i64 %b, i64* %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]], i64* [[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, i64* %ptr, align 8
338   ret i1 %overflow.1
341 define i1 @test4_no_icmp_ne_logical(i64 %a, i64 %b, i64* %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]], i64* [[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, i64* %ptr, align 8
359   ret i1 %overflow.1
362 attributes #0 = { nounwind readnone speculatable willreturn }