@@ -11,7 +11,7 @@ define i32 @test1(i32 %a, i32 %b) nounwind ssp {
1111; CHECK-NEXT: [[TMP0:%.*]] = extractvalue { i32, i1 } [[SADD]], 1
1212; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
1313; CHECK: if.then:
14- ; CHECK-NEXT: tail call void @throwAnExceptionOrWhatever() #[[ATTR2 :[0-9]+]]
14+ ; CHECK-NEXT: tail call void @throwAnExceptionOrWhatever() #[[ATTR3 :[0-9]+]]
1515; CHECK-NEXT: br label [[IF_END]]
1616; CHECK: if.end:
1717; CHECK-NEXT: [[SADD_RESULT:%.*]] = extractvalue { i32, i1 } [[SADD]], 0
@@ -49,7 +49,7 @@ define i32 @test2(i32 %a, i32 %b, ptr %P) nounwind ssp {
4949; CHECK-NEXT: [[TMP0:%.*]] = icmp ugt i64 [[ADD_OFF]], 4294967295
5050; CHECK-NEXT: br i1 [[TMP0]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
5151; CHECK: if.then:
52- ; CHECK-NEXT: tail call void @throwAnExceptionOrWhatever() #[[ATTR2 ]]
52+ ; CHECK-NEXT: tail call void @throwAnExceptionOrWhatever() #[[ATTR3 ]]
5353; CHECK-NEXT: br label [[IF_END]]
5454; CHECK: if.end:
5555; CHECK-NEXT: [[CONV9:%.*]] = trunc i64 [[ADD]] to i32
@@ -86,7 +86,7 @@ define i64 @test3(i32 %a, i32 %b) nounwind ssp {
8686; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 [[TMP0]], -4294967296
8787; CHECK-NEXT: br i1 [[TMP1]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
8888; CHECK: if.then:
89- ; CHECK-NEXT: tail call void @throwAnExceptionOrWhatever() #[[ATTR2 ]]
89+ ; CHECK-NEXT: tail call void @throwAnExceptionOrWhatever() #[[ATTR3 ]]
9090; CHECK-NEXT: br label [[IF_END]]
9191; CHECK: if.end:
9292; CHECK-NEXT: ret i64 [[ADD]]
@@ -116,7 +116,7 @@ define zeroext i8 @test4(i8 signext %a, i8 signext %b) nounwind ssp {
116116; CHECK-NEXT: [[CMP:%.*]] = extractvalue { i8, i1 } [[SADD]], 1
117117; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
118118; CHECK: if.then:
119- ; CHECK-NEXT: tail call void @throwAnExceptionOrWhatever() #[[ATTR2 ]]
119+ ; CHECK-NEXT: tail call void @throwAnExceptionOrWhatever() #[[ATTR3 ]]
120120; CHECK-NEXT: unreachable
121121; CHECK: if.end:
122122; CHECK-NEXT: [[SADD_RESULT:%.*]] = extractvalue { i8, i1 } [[SADD]], 0
@@ -150,7 +150,7 @@ define i32 @test8(i64 %a, i64 %b) nounwind ssp {
150150; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 [[TMP0]], -4294967296
151151; CHECK-NEXT: br i1 [[TMP1]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
152152; CHECK: if.then:
153- ; CHECK-NEXT: tail call void @throwAnExceptionOrWhatever() #[[ATTR2 ]]
153+ ; CHECK-NEXT: tail call void @throwAnExceptionOrWhatever() #[[ATTR3 ]]
154154; CHECK-NEXT: br label [[IF_END]]
155155; CHECK: if.end:
156156; CHECK-NEXT: [[CONV9:%.*]] = trunc i64 [[ADD]] to i32
@@ -171,3 +171,99 @@ if.end:
171171 ret i32 %conv9
172172}
173173
174+ define i32 @uadd_no_overflow (i32 %a , i32 %b ) {
175+ ; CHECK-LABEL: @uadd_no_overflow(
176+ ; CHECK-NEXT: [[VAL:%.*]] = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[A:%.*]], i32 [[B:%.*]])
177+ ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i32, i1 } [[VAL]], 1
178+ ; CHECK-NEXT: [[NOWRAP:%.*]] = xor i1 [[OV]], true
179+ ; CHECK-NEXT: tail call void @llvm.assume(i1 [[NOWRAP]])
180+ ; CHECK-NEXT: [[RES:%.*]] = extractvalue { i32, i1 } [[VAL]], 0
181+ ; CHECK-NEXT: ret i32 [[RES]]
182+ ;
183+ %val = tail call { i32 , i1 } @llvm.uadd.with.overflow.i32 (i32 %a , i32 %b )
184+ %ov = extractvalue { i32 , i1 } %val , 1
185+ %nowrap = xor i1 %ov , true
186+ tail call void @llvm.assume (i1 %nowrap )
187+ %res = extractvalue { i32 , i1 } %val , 0
188+ ret i32 %res
189+ }
190+
191+ define i32 @smul_no_overflow (i32 %a , i32 %b ) {
192+ ; CHECK-LABEL: @smul_no_overflow(
193+ ; CHECK-NEXT: [[VAL:%.*]] = tail call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[A:%.*]], i32 [[B:%.*]])
194+ ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i32, i1 } [[VAL]], 1
195+ ; CHECK-NEXT: [[NOWRAP:%.*]] = xor i1 [[OV]], true
196+ ; CHECK-NEXT: tail call void @llvm.assume(i1 [[NOWRAP]])
197+ ; CHECK-NEXT: [[RES:%.*]] = extractvalue { i32, i1 } [[VAL]], 0
198+ ; CHECK-NEXT: ret i32 [[RES]]
199+ ;
200+ %val = tail call { i32 , i1 } @llvm.smul.with.overflow.i32 (i32 %a , i32 %b )
201+ %ov = extractvalue { i32 , i1 } %val , 1
202+ %nowrap = xor i1 %ov , true
203+ tail call void @llvm.assume (i1 %nowrap )
204+ %res = extractvalue { i32 , i1 } %val , 0
205+ ret i32 %res
206+ }
207+
208+ define i32 @smul_overflow (i32 %a , i32 %b ) {
209+ ; CHECK-LABEL: @smul_overflow(
210+ ; CHECK-NEXT: [[VAL:%.*]] = tail call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[A:%.*]], i32 [[B:%.*]])
211+ ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i32, i1 } [[VAL]], 1
212+ ; CHECK-NEXT: tail call void @llvm.assume(i1 [[OV]])
213+ ; CHECK-NEXT: [[RES:%.*]] = extractvalue { i32, i1 } [[VAL]], 0
214+ ; CHECK-NEXT: ret i32 [[RES]]
215+ ;
216+ %val = tail call { i32 , i1 } @llvm.smul.with.overflow.i32 (i32 %a , i32 %b )
217+ %ov = extractvalue { i32 , i1 } %val , 1
218+ tail call void @llvm.assume (i1 %ov )
219+ %res = extractvalue { i32 , i1 } %val , 0
220+ ret i32 %res
221+ }
222+
223+ define i32 @uadd_no_overflow_invalid1 (i32 %a , i32 %b , i1 %cond ) {
224+ ; CHECK-LABEL: @uadd_no_overflow_invalid1(
225+ ; CHECK-NEXT: [[VAL:%.*]] = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[A:%.*]], i32 [[B:%.*]])
226+ ; CHECK-NEXT: [[RES:%.*]] = extractvalue { i32, i1 } [[VAL]], 0
227+ ; CHECK-NEXT: call void @use(i32 [[RES]])
228+ ; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
229+ ; CHECK: if.then:
230+ ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i32, i1 } [[VAL]], 1
231+ ; CHECK-NEXT: [[NOWRAP:%.*]] = xor i1 [[OV]], true
232+ ; CHECK-NEXT: tail call void @llvm.assume(i1 [[NOWRAP]])
233+ ; CHECK-NEXT: ret i32 [[RES]]
234+ ; CHECK: if.else:
235+ ; CHECK-NEXT: ret i32 0
236+ ;
237+ %val = tail call { i32 , i1 } @llvm.uadd.with.overflow.i32 (i32 %a , i32 %b )
238+ %res = extractvalue { i32 , i1 } %val , 0
239+ call void @use (i32 %res )
240+ br i1 %cond , label %if.then , label %if.else
241+ if.then:
242+ %ov = extractvalue { i32 , i1 } %val , 1
243+ %nowrap = xor i1 %ov , true
244+ tail call void @llvm.assume (i1 %nowrap )
245+ ret i32 %res
246+ if.else:
247+ ret i32 0
248+ }
249+
250+ define i32 @uadd_no_overflow_invalid2 (i32 %a , i32 %b , i1 %cond ) {
251+ ; CHECK-LABEL: @uadd_no_overflow_invalid2(
252+ ; CHECK-NEXT: [[VAL:%.*]] = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[A:%.*]], i32 [[B:%.*]])
253+ ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i32, i1 } [[VAL]], 1
254+ ; CHECK-NEXT: [[NOWRAP:%.*]] = xor i1 [[OV]], true
255+ ; CHECK-NEXT: call void @use(i32 0)
256+ ; CHECK-NEXT: tail call void @llvm.assume(i1 [[NOWRAP]])
257+ ; CHECK-NEXT: [[RES:%.*]] = extractvalue { i32, i1 } [[VAL]], 0
258+ ; CHECK-NEXT: ret i32 [[RES]]
259+ ;
260+ %val = tail call { i32 , i1 } @llvm.uadd.with.overflow.i32 (i32 %a , i32 %b )
261+ %ov = extractvalue { i32 , i1 } %val , 1
262+ %nowrap = xor i1 %ov , true
263+ call void @use (i32 0 ) ; It is not guaranteed to transfer execution to its successors
264+ tail call void @llvm.assume (i1 %nowrap )
265+ %res = extractvalue { i32 , i1 } %val , 0
266+ ret i32 %res
267+ }
268+
269+ declare void @use (i32 )
0 commit comments