Files
clang-p2996/llvm/test/Transforms/CorrelatedValuePropagation/overflows.ll
Nikita Popov fdc6977ff3 [LVI] Look through extractvalue of insertvalue
This addresses the issue mentioned on D19867. When we simplify
with.overflow instructions in CVP, we leave behind extractvalue
of insertvalue sequences that LVI no longer understands. This
means that we can not simplify any instructions based on the
with.overflow anymore (until some over pass like InstCombine
cleans them up).

This patch extends LVI extractvalue handling by calling
SimplifyExtractValueInst (which doesn't do anything more than
constant folding + looking through insertvalue) and using the block
value of the simplification.

A possible alternative would be to do something similar to
SimplifyIndVars, where we instead directly try to replace
extractvalue users of the with.overflow. This would need some
additional structural changes to CVP, as it's currently not legal
to remove anything but the current instruction -- we'd have to
introduce a worklist with instructions scheduled for deletion or similar.

Differential Revision: https://reviews.llvm.org/D67035

llvm-svn: 371306
2019-09-07 12:03:59 +00:00

1097 lines
41 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -correlated-propagation < %s | FileCheck %s
; Check that debug locations are preserved. For more info see:
; https://llvm.org/docs/SourceLevelDebugging.html#fixing-errors
; RUN: opt < %s -enable-debugify -correlated-propagation -S 2>&1 | \
; RUN: FileCheck %s -check-prefix=DEBUG
; DEBUG: CheckModuleDebugify: PASS
declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32)
declare { i32, i1 } @llvm.ssub.with.overflow.i32(i32, i32)
declare { i32, i1 } @llvm.smul.with.overflow.i32(i32, i32)
declare { i32, i1 } @llvm.uadd.with.overflow.i32(i32, i32)
declare { i32, i1 } @llvm.usub.with.overflow.i32(i32, i32)
declare { i32, i1 } @llvm.umul.with.overflow.i32(i32, i32)
declare { i8, i1 } @llvm.umul.with.overflow.i8(i8, i8)
declare { <2 x i32>, <2 x i1> } @llvm.uadd.with.overflow.v2i32(<2 x i32>, <2 x i32>)
declare i8 @llvm.uadd.sat.i8(i8, i8)
declare i8 @llvm.sadd.sat.i8(i8, i8)
declare i8 @llvm.usub.sat.i8(i8, i8)
declare i8 @llvm.ssub.sat.i8(i8, i8)
declare <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8>, <2 x i8>)
declare void @llvm.trap()
define i32 @signed_add(i32 %x, i32 %y) {
; CHECK-LABEL: @signed_add(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[Y:%.*]], 0
; CHECK-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[LOR_LHS_FALSE:%.*]]
; CHECK: land.lhs.true:
; CHECK-NEXT: [[TMP0:%.*]] = sub nsw i32 2147483647, [[Y]]
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[TMP0]], 0
; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1
; CHECK-NEXT: br i1 [[TMP2]], label [[TRAP:%.*]], label [[CONT:%.*]]
; CHECK: trap:
; CHECK-NEXT: tail call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: cont:
; CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[TMP3]], [[X:%.*]]
; CHECK-NEXT: br i1 [[CMP1]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]]
; CHECK: lor.lhs.false:
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[Y]], 0
; CHECK-NEXT: br i1 [[CMP2]], label [[LAND_LHS_TRUE3:%.*]], label [[COND_FALSE]]
; CHECK: land.lhs.true3:
; CHECK-NEXT: [[TMP4:%.*]] = sub nsw i32 -2147483648, [[Y]]
; CHECK-NEXT: [[TMP5:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[TMP4]], 0
; CHECK-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1
; CHECK-NEXT: br i1 [[TMP6]], label [[TRAP]], label [[CONT4:%.*]]
; CHECK: cont4:
; CHECK-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0
; CHECK-NEXT: [[CMP5:%.*]] = icmp sgt i32 [[TMP7]], [[X]]
; CHECK-NEXT: br i1 [[CMP5]], label [[COND_END]], label [[COND_FALSE]]
; CHECK: cond.false:
; CHECK-NEXT: [[TMP8:%.*]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[X]], i32 [[Y]])
; CHECK-NEXT: [[TMP9:%.*]] = extractvalue { i32, i1 } [[TMP8]], 0
; CHECK-NEXT: [[TMP10:%.*]] = extractvalue { i32, i1 } [[TMP8]], 1
; CHECK-NEXT: br i1 [[TMP10]], label [[TRAP]], label [[COND_END]]
; CHECK: cond.end:
; CHECK-NEXT: [[COND:%.*]] = phi i32 [ 0, [[CONT4]] ], [ 0, [[CONT]] ], [ [[TMP9]], [[COND_FALSE]] ]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%cmp = icmp sgt i32 %y, 0
br i1 %cmp, label %land.lhs.true, label %lor.lhs.false
land.lhs.true: ; preds = %entry
%0 = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 2147483647, i32 %y)
%1 = extractvalue { i32, i1 } %0, 1
br i1 %1, label %trap, label %cont
trap: ; preds = %land.lhs.true, %land.lhs.true3, %cond.false
tail call void @llvm.trap()
unreachable
cont: ; preds = %land.lhs.true
%2 = extractvalue { i32, i1 } %0, 0
%cmp1 = icmp slt i32 %2, %x
br i1 %cmp1, label %cond.end, label %cond.false
lor.lhs.false: ; preds = %entry
%cmp2 = icmp slt i32 %y, 0
br i1 %cmp2, label %land.lhs.true3, label %cond.false
land.lhs.true3: ; preds = %lor.lhs.false
%3 = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 -2147483648, i32 %y)
%4 = extractvalue { i32, i1 } %3, 1
br i1 %4, label %trap, label %cont4
cont4: ; preds = %land.lhs.true3
%5 = extractvalue { i32, i1 } %3, 0
%cmp5 = icmp sgt i32 %5, %x
br i1 %cmp5, label %cond.end, label %cond.false
cond.false: ; preds = %cont, %cont4, %lor.lhs.false
%6 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 %y)
%7 = extractvalue { i32, i1 } %6, 0
%8 = extractvalue { i32, i1 } %6, 1
br i1 %8, label %trap, label %cond.end
cond.end: ; preds = %cond.false, %cont, %cont4
%cond = phi i32 [ 0, %cont4 ], [ 0, %cont ], [ %7, %cond.false ]
ret i32 %cond
}
define i32 @unsigned_add(i32 %x, i32 %y) {
; CHECK-LABEL: @unsigned_add(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = sub nuw i32 -1, [[Y:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[TMP0]], 0
; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1
; CHECK-NEXT: br i1 [[TMP2]], label [[TRAP:%.*]], label [[CONT:%.*]]
; CHECK: trap:
; CHECK-NEXT: tail call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: cont:
; CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[TMP3]], [[X:%.*]]
; CHECK-NEXT: br i1 [[CMP1]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: [[TMP4:%.*]] = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 [[X]], i32 [[Y]])
; CHECK-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP4]], 0
; CHECK-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP4]], 1
; CHECK-NEXT: br i1 [[TMP6]], label [[TRAP]], label [[COND_END]]
; CHECK: cond.end:
; CHECK-NEXT: [[COND:%.*]] = phi i32 [ 0, [[CONT]] ], [ [[TMP5]], [[COND_FALSE]] ]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%0 = tail call { i32, i1 } @llvm.usub.with.overflow.i32(i32 -1, i32 %y)
%1 = extractvalue { i32, i1 } %0, 1
br i1 %1, label %trap, label %cont
trap: ; preds = %cond.false, %entry
tail call void @llvm.trap()
unreachable
cont: ; preds = %entry
%2 = extractvalue { i32, i1 } %0, 0
%cmp1 = icmp ult i32 %2, %x
br i1 %cmp1, label %cond.end, label %cond.false
cond.false: ; preds = %cont
%3 = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %x, i32 %y)
%4 = extractvalue { i32, i1 } %3, 0
%5 = extractvalue { i32, i1 } %3, 1
br i1 %5, label %trap, label %cond.end
cond.end: ; preds = %cond.false, %cont
%cond = phi i32 [ 0, %cont ], [ %4, %cond.false ]
ret i32 %cond
}
define i32 @signed_sub(i32 %x, i32 %y) {
; CHECK-LABEL: @signed_sub(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[Y:%.*]], 0
; CHECK-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[LOR_LHS_FALSE:%.*]]
; CHECK: land.lhs.true:
; CHECK-NEXT: [[TMP0:%.*]] = add nsw i32 [[Y]], 2147483647
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[TMP0]], 0
; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1
; CHECK-NEXT: br i1 [[TMP2]], label [[TRAP:%.*]], label [[CONT:%.*]]
; CHECK: trap:
; CHECK-NEXT: tail call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: cont:
; CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0
; CHECK-NEXT: [[CMP1:%.*]] = icmp slt i32 [[TMP3]], [[X:%.*]]
; CHECK-NEXT: br i1 [[CMP1]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]]
; CHECK: lor.lhs.false:
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[Y]], 0
; CHECK-NEXT: br i1 [[CMP2]], label [[COND_FALSE]], label [[LAND_LHS_TRUE3:%.*]]
; CHECK: land.lhs.true3:
; CHECK-NEXT: [[TMP4:%.*]] = add nsw i32 [[Y]], -2147483648
; CHECK-NEXT: [[TMP5:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[TMP4]], 0
; CHECK-NEXT: [[TMP6:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1
; CHECK-NEXT: br i1 [[TMP6]], label [[TRAP]], label [[CONT4:%.*]]
; CHECK: cont4:
; CHECK-NEXT: [[TMP7:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0
; CHECK-NEXT: [[CMP5:%.*]] = icmp sgt i32 [[TMP7]], [[X]]
; CHECK-NEXT: br i1 [[CMP5]], label [[COND_END]], label [[COND_FALSE]]
; CHECK: cond.false:
; CHECK-NEXT: [[TMP8:%.*]] = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 [[X]], i32 [[Y]])
; CHECK-NEXT: [[TMP9:%.*]] = extractvalue { i32, i1 } [[TMP8]], 0
; CHECK-NEXT: [[TMP10:%.*]] = extractvalue { i32, i1 } [[TMP8]], 1
; CHECK-NEXT: br i1 [[TMP10]], label [[TRAP]], label [[COND_END]]
; CHECK: cond.end:
; CHECK-NEXT: [[COND:%.*]] = phi i32 [ 0, [[CONT4]] ], [ 0, [[CONT]] ], [ [[TMP9]], [[COND_FALSE]] ]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%cmp = icmp slt i32 %y, 0
br i1 %cmp, label %land.lhs.true, label %lor.lhs.false
land.lhs.true: ; preds = %entry
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %y, i32 2147483647)
%1 = extractvalue { i32, i1 } %0, 1
br i1 %1, label %trap, label %cont
trap: ; preds = %land.lhs.true, %land.lhs.true3, %cond.false
tail call void @llvm.trap()
unreachable
cont: ; preds = %land.lhs.true
%2 = extractvalue { i32, i1 } %0, 0
%cmp1 = icmp slt i32 %2, %x
br i1 %cmp1, label %cond.end, label %cond.false
lor.lhs.false: ; preds = %entry
%cmp2 = icmp eq i32 %y, 0
br i1 %cmp2, label %cond.false, label %land.lhs.true3
land.lhs.true3: ; preds = %lor.lhs.false
%3 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %y, i32 -2147483648)
%4 = extractvalue { i32, i1 } %3, 1
br i1 %4, label %trap, label %cont4
cont4: ; preds = %land.lhs.true3
%5 = extractvalue { i32, i1 } %3, 0
%cmp5 = icmp sgt i32 %5, %x
br i1 %cmp5, label %cond.end, label %cond.false
cond.false: ; preds = %lor.lhs.false, %cont, %cont4
%6 = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %x, i32 %y)
%7 = extractvalue { i32, i1 } %6, 0
%8 = extractvalue { i32, i1 } %6, 1
br i1 %8, label %trap, label %cond.end
cond.end: ; preds = %cond.false, %cont, %cont4
%cond = phi i32 [ 0, %cont4 ], [ 0, %cont ], [ %7, %cond.false ]
ret i32 %cond
}
define i32 @unsigned_sub(i32 %x, i32 %y) {
; CHECK-LABEL: @unsigned_sub(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: [[TMP0:%.*]] = tail call { i32, i1 } @llvm.usub.with.overflow.i32(i32 [[X]], i32 [[Y]])
; CHECK-NEXT: [[TMP1:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0
; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1
; CHECK-NEXT: br i1 [[TMP2]], label [[TRAP:%.*]], label [[COND_END]]
; CHECK: trap:
; CHECK-NEXT: tail call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: cond.end:
; CHECK-NEXT: [[COND:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[TMP1]], [[COND_FALSE]] ]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%cmp = icmp ult i32 %x, %y
br i1 %cmp, label %cond.end, label %cond.false
cond.false: ; preds = %entry
%0 = tail call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %x, i32 %y)
%1 = extractvalue { i32, i1 } %0, 0
%2 = extractvalue { i32, i1 } %0, 1
br i1 %2, label %trap, label %cond.end
trap: ; preds = %cond.false
tail call void @llvm.trap()
unreachable
cond.end: ; preds = %cond.false, %entry
%cond = phi i32 [ 0, %entry ], [ %1, %cond.false ]
ret i32 %cond
}
define i32 @signed_add_r1(i32 %x) {
; CHECK-LABEL: @signed_add_r1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 2147483647
; CHECK-NEXT: br i1 [[CMP]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: [[TMP0:%.*]] = add nsw i32 [[X]], 1
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[TMP0]], 0
; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0
; CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1
; CHECK-NEXT: br i1 [[TMP3]], label [[TRAP:%.*]], label [[COND_END]]
; CHECK: trap:
; CHECK-NEXT: tail call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: cond.end:
; CHECK-NEXT: [[COND:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[TMP2]], [[COND_FALSE]] ]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%cmp = icmp eq i32 %x, 2147483647
br i1 %cmp, label %cond.end, label %cond.false
cond.false: ; preds = %entry
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 1)
%1 = extractvalue { i32, i1 } %0, 0
%2 = extractvalue { i32, i1 } %0, 1
br i1 %2, label %trap, label %cond.end
trap: ; preds = %cond.false
tail call void @llvm.trap()
unreachable
cond.end: ; preds = %cond.false, %entry
%cond = phi i32 [ 0, %entry ], [ %1, %cond.false ]
ret i32 %cond
}
define i32 @unsigned_add_r1(i32 %x) {
; CHECK-LABEL: @unsigned_add_r1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], -1
; CHECK-NEXT: br i1 [[CMP]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: [[TMP0:%.*]] = add nuw i32 [[X]], 1
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[TMP0]], 0
; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0
; CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1
; CHECK-NEXT: br i1 [[TMP3]], label [[TRAP:%.*]], label [[COND_END]]
; CHECK: trap:
; CHECK-NEXT: tail call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: cond.end:
; CHECK-NEXT: [[COND:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[TMP2]], [[COND_FALSE]] ]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%cmp = icmp eq i32 %x, -1
br i1 %cmp, label %cond.end, label %cond.false
cond.false: ; preds = %entry
%0 = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %x, i32 1)
%1 = extractvalue { i32, i1 } %0, 0
%2 = extractvalue { i32, i1 } %0, 1
br i1 %2, label %trap, label %cond.end
trap: ; preds = %cond.false
tail call void @llvm.trap()
unreachable
cond.end: ; preds = %cond.false, %entry
%cond = phi i32 [ 0, %entry ], [ %1, %cond.false ]
ret i32 %cond
}
define i32 @signed_sub_r1(i32 %x) {
; CHECK-LABEL: @signed_sub_r1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], -2147483648
; CHECK-NEXT: br i1 [[CMP]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: [[TMP0:%.*]] = sub nsw i32 [[X]], 1
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[TMP0]], 0
; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0
; CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1
; CHECK-NEXT: br i1 [[TMP3]], label [[TRAP:%.*]], label [[COND_END]]
; CHECK: trap:
; CHECK-NEXT: tail call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: cond.end:
; CHECK-NEXT: [[COND:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[TMP2]], [[COND_FALSE]] ]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%cmp = icmp eq i32 %x, -2147483648
br i1 %cmp, label %cond.end, label %cond.false
cond.false: ; preds = %entry
%0 = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %x, i32 1)
%1 = extractvalue { i32, i1 } %0, 0
%2 = extractvalue { i32, i1 } %0, 1
br i1 %2, label %trap, label %cond.end
trap: ; preds = %cond.false
tail call void @llvm.trap()
unreachable
cond.end: ; preds = %cond.false, %entry
%cond = phi i32 [ 0, %entry ], [ %1, %cond.false ]
ret i32 %cond
}
define i32 @unsigned_sub_r1(i32 %x) {
; CHECK-LABEL: @unsigned_sub_r1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 0
; CHECK-NEXT: br i1 [[CMP]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: [[TMP0:%.*]] = sub nuw i32 [[X]], 1
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[TMP0]], 0
; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0
; CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1
; CHECK-NEXT: br i1 [[TMP3]], label [[TRAP:%.*]], label [[COND_END]]
; CHECK: trap:
; CHECK-NEXT: tail call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: cond.end:
; CHECK-NEXT: [[COND:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[TMP2]], [[COND_FALSE]] ]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%cmp = icmp eq i32 %x, 0
br i1 %cmp, label %cond.end, label %cond.false
cond.false: ; preds = %entry
%0 = tail call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %x, i32 1)
%1 = extractvalue { i32, i1 } %0, 0
%2 = extractvalue { i32, i1 } %0, 1
br i1 %2, label %trap, label %cond.end
trap: ; preds = %cond.false
tail call void @llvm.trap()
unreachable
cond.end: ; preds = %cond.false, %entry
%cond = phi i32 [ 0, %entry ], [ %1, %cond.false ]
ret i32 %cond
}
define i32 @signed_add_rn1(i32 %x) {
; CHECK-LABEL: @signed_add_rn1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], -2147483648
; CHECK-NEXT: br i1 [[CMP]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: [[TMP0:%.*]] = add nsw i32 [[X]], -1
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[TMP0]], 0
; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0
; CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1
; CHECK-NEXT: br i1 [[TMP3]], label [[TRAP:%.*]], label [[COND_END]]
; CHECK: trap:
; CHECK-NEXT: tail call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: cond.end:
; CHECK-NEXT: [[COND:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[TMP2]], [[COND_FALSE]] ]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%cmp = icmp eq i32 %x, -2147483648
br i1 %cmp, label %cond.end, label %cond.false
cond.false: ; preds = %entry
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 -1)
%1 = extractvalue { i32, i1 } %0, 0
%2 = extractvalue { i32, i1 } %0, 1
br i1 %2, label %trap, label %cond.end
trap: ; preds = %cond.false
tail call void @llvm.trap()
unreachable
cond.end: ; preds = %cond.false, %entry
%cond = phi i32 [ 0, %entry ], [ %1, %cond.false ]
ret i32 %cond
}
define i32 @signed_sub_rn1(i32 %x) {
; CHECK-LABEL: @signed_sub_rn1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 2147483647
; CHECK-NEXT: br i1 [[CMP]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: [[TMP0:%.*]] = sub nsw i32 [[X]], -1
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[TMP0]], 0
; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 0
; CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1
; CHECK-NEXT: br i1 [[TMP3]], label [[TRAP:%.*]], label [[COND_END]]
; CHECK: trap:
; CHECK-NEXT: tail call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: cond.end:
; CHECK-NEXT: [[COND:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[TMP2]], [[COND_FALSE]] ]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%cmp = icmp eq i32 %x, 2147483647
br i1 %cmp, label %cond.end, label %cond.false
cond.false: ; preds = %entry
%0 = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %x, i32 -1)
%1 = extractvalue { i32, i1 } %0, 0
%2 = extractvalue { i32, i1 } %0, 1
br i1 %2, label %trap, label %cond.end
trap: ; preds = %cond.false
tail call void @llvm.trap()
unreachable
cond.end: ; preds = %cond.false, %entry
%cond = phi i32 [ 0, %entry ], [ %1, %cond.false ]
ret i32 %cond
}
define i32 @unsigned_mul(i32 %x) {
; CHECK-LABEL: @unsigned_mul(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[X:%.*]], 10000
; CHECK-NEXT: br i1 [[CMP]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: [[MULO1:%.*]] = mul nuw i32 [[X]], 100
; CHECK-NEXT: [[TMP0:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[MULO1]], 0
; CHECK-NEXT: [[RES:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0
; CHECK-NEXT: [[OV:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1
; CHECK-NEXT: br i1 [[OV]], label [[TRAP:%.*]], label [[COND_END]]
; CHECK: trap:
; CHECK-NEXT: tail call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: cond.end:
; CHECK-NEXT: [[COND:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[RES]], [[COND_FALSE]] ]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%cmp = icmp ugt i32 %x, 10000
br i1 %cmp, label %cond.end, label %cond.false
cond.false: ; preds = %entry
%mulo = tail call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %x, i32 100)
%res = extractvalue { i32, i1 } %mulo, 0
%ov = extractvalue { i32, i1 } %mulo, 1
br i1 %ov, label %trap, label %cond.end
trap: ; preds = %cond.false
tail call void @llvm.trap()
unreachable
cond.end: ; preds = %cond.false, %entry
%cond = phi i32 [ 0, %entry ], [ %res, %cond.false ]
ret i32 %cond
}
define i32 @signed_mul(i32 %x) {
; CHECK-LABEL: @signed_mul(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[X:%.*]], 10000
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[X]], -10000
; CHECK-NEXT: [[CMP3:%.*]] = or i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT: br i1 [[CMP3]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]]
; CHECK: cond.false:
; CHECK-NEXT: [[MULO1:%.*]] = mul nsw i32 [[X]], 100
; CHECK-NEXT: [[TMP0:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[MULO1]], 0
; CHECK-NEXT: [[RES:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0
; CHECK-NEXT: [[OV:%.*]] = extractvalue { i32, i1 } [[TMP0]], 1
; CHECK-NEXT: br i1 [[OV]], label [[TRAP:%.*]], label [[COND_END]]
; CHECK: trap:
; CHECK-NEXT: tail call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: cond.end:
; CHECK-NEXT: [[COND:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[RES]], [[COND_FALSE]] ]
; CHECK-NEXT: ret i32 [[COND]]
;
entry:
%cmp1 = icmp sgt i32 %x, 10000
%cmp2 = icmp slt i32 %x, -10000
%cmp3 = or i1 %cmp1, %cmp2
br i1 %cmp3, label %cond.end, label %cond.false
cond.false: ; preds = %entry
%mulo = tail call { i32, i1 } @llvm.smul.with.overflow.i32(i32 %x, i32 100)
%res = extractvalue { i32, i1 } %mulo, 0
%ov = extractvalue { i32, i1 } %mulo, 1
br i1 %ov, label %trap, label %cond.end
trap: ; preds = %cond.false
tail call void @llvm.trap()
unreachable
cond.end: ; preds = %cond.false, %entry
%cond = phi i32 [ 0, %entry ], [ %res, %cond.false ]
ret i32 %cond
}
declare i32 @bar(i32)
define void @unsigned_loop(i32 %i) {
; CHECK-LABEL: @unsigned_loop(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i32 [[I:%.*]], 0
; CHECK-NEXT: br i1 [[CMP3]], label [[WHILE_END:%.*]], label [[WHILE_BODY_PREHEADER:%.*]]
; CHECK: while.body.preheader:
; CHECK-NEXT: br label [[WHILE_BODY:%.*]]
; CHECK: while.body:
; CHECK-NEXT: [[I_ADDR_04:%.*]] = phi i32 [ [[TMP3:%.*]], [[CONT:%.*]] ], [ [[I]], [[WHILE_BODY_PREHEADER]] ]
; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @bar(i32 [[I_ADDR_04]])
; CHECK-NEXT: [[TMP0:%.*]] = sub nuw i32 [[I_ADDR_04]], 1
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[TMP0]], 0
; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1
; CHECK-NEXT: br i1 [[TMP2]], label [[TRAP:%.*]], label [[CONT]]
; CHECK: trap:
; CHECK-NEXT: tail call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: cont:
; CHECK-NEXT: [[TMP3]] = extractvalue { i32, i1 } [[TMP1]], 0
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP3]], 0
; CHECK-NEXT: br i1 [[CMP]], label [[WHILE_END]], label [[WHILE_BODY]]
; CHECK: while.end:
; CHECK-NEXT: ret void
;
entry:
%cmp3 = icmp eq i32 %i, 0
br i1 %cmp3, label %while.end, label %while.body.preheader
while.body.preheader: ; preds = %entry
br label %while.body
while.body: ; preds = %while.body.preheader, %cont
%i.addr.04 = phi i32 [ %2, %cont ], [ %i, %while.body.preheader ]
%call = tail call i32 @bar(i32 %i.addr.04)
%0 = tail call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %i.addr.04, i32 1)
%1 = extractvalue { i32, i1 } %0, 1
br i1 %1, label %trap, label %cont
trap: ; preds = %while.body
tail call void @llvm.trap()
unreachable
cont: ; preds = %while.body
%2 = extractvalue { i32, i1 } %0, 0
%cmp = icmp eq i32 %2, 0
br i1 %cmp, label %while.end, label %while.body
while.end: ; preds = %cont, %entry
ret void
}
define void @intrinsic_into_phi(i32 %n) {
; CHECK-LABEL: @intrinsic_into_phi(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[CONT:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[TMP0:%.*]] = add nsw i32 [[DOTLCSSA:%.*]], 1
; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[TMP0]], 0
; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { i32, i1 } [[TMP1]], 1
; CHECK-NEXT: br i1 [[TMP2]], label [[TRAP:%.*]], label [[CONT]]
; CHECK: trap:
; CHECK-NEXT: tail call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: cont:
; CHECK-NEXT: [[TMP3:%.*]] = phi { i32, i1 } [ zeroinitializer, [[ENTRY:%.*]] ], [ [[TMP1]], [[FOR_COND:%.*]] ]
; CHECK-NEXT: [[TMP4:%.*]] = extractvalue { i32, i1 } [[TMP3]], 0
; CHECK-NEXT: [[CALL9:%.*]] = tail call i32 @bar(i32 [[TMP4]])
; CHECK-NEXT: [[TOBOOL10:%.*]] = icmp eq i32 [[CALL9]], 0
; CHECK-NEXT: br i1 [[TOBOOL10]], label [[WHILE_END:%.*]], label [[WHILE_BODY_PREHEADER:%.*]]
; CHECK: while.body.preheader:
; CHECK-NEXT: br label [[WHILE_BODY:%.*]]
; CHECK: while.cond:
; CHECK-NEXT: [[TMP5:%.*]] = extractvalue { i32, i1 } [[TMP7:%.*]], 0
; CHECK-NEXT: [[CALL:%.*]] = tail call i32 @bar(i32 [[TMP5]])
; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[CALL]], 0
; CHECK-NEXT: br i1 [[TOBOOL]], label [[WHILE_END]], label [[WHILE_BODY]]
; CHECK: while.body:
; CHECK-NEXT: [[TMP6:%.*]] = phi i32 [ [[TMP5]], [[WHILE_COND:%.*]] ], [ [[TMP4]], [[WHILE_BODY_PREHEADER]] ]
; CHECK-NEXT: [[TMP7]] = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 [[TMP6]], i32 1)
; CHECK-NEXT: [[TMP8:%.*]] = extractvalue { i32, i1 } [[TMP7]], 1
; CHECK-NEXT: br i1 [[TMP8]], label [[TRAP]], label [[WHILE_COND]]
; CHECK: while.end:
; CHECK-NEXT: [[DOTLCSSA]] = phi i32 [ [[TMP4]], [[CONT]] ], [ [[TMP5]], [[WHILE_COND]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[DOTLCSSA]], [[N:%.*]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_COND]], label [[CLEANUP2:%.*]]
; CHECK: cleanup2:
; CHECK-NEXT: ret void
;
entry:
br label %cont
for.cond: ; preds = %while.end
%0 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %.lcssa, i32 1)
%1 = extractvalue { i32, i1 } %0, 1
br i1 %1, label %trap, label %cont
trap: ; preds = %for.cond, %while.body
tail call void @llvm.trap()
unreachable
cont: ; preds = %entry, %for.cond
%2 = phi { i32, i1 } [ zeroinitializer, %entry ], [ %0, %for.cond ]
%3 = extractvalue { i32, i1 } %2, 0
%call9 = tail call i32 @bar(i32 %3)
%tobool10 = icmp eq i32 %call9, 0
br i1 %tobool10, label %while.end, label %while.body.preheader
while.body.preheader: ; preds = %cont
br label %while.body
while.cond: ; preds = %while.body
%4 = extractvalue { i32, i1 } %6, 0
%call = tail call i32 @bar(i32 %4)
%tobool = icmp eq i32 %call, 0
br i1 %tobool, label %while.end, label %while.body
while.body: ; preds = %while.body.preheader, %while.cond
%5 = phi i32 [ %4, %while.cond ], [ %3, %while.body.preheader ]
%6 = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %5, i32 1)
%7 = extractvalue { i32, i1 } %6, 1
br i1 %7, label %trap, label %while.cond
while.end: ; preds = %while.cond, %cont
%.lcssa = phi i32 [ %3, %cont ], [ %4, %while.cond ]
%cmp = icmp slt i32 %.lcssa, %n
br i1 %cmp, label %for.cond, label %cleanup2
cleanup2: ; preds = %while.end
ret void
}
define { i8, i1 } @signed_mul_constant_folding() {
; CHECK-LABEL: @signed_mul_constant_folding(
; CHECK-NEXT: ret { i8, i1 } { i8 2, i1 false }
;
%mul = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 1, i8 2)
ret { i8, i1 } %mul
}
define { <2 x i32>, <2 x i1> } @uaddo_vec(<2 x i32> %a) {
; CHECK-LABEL: @uaddo_vec(
; CHECK-NEXT: [[ADD:%.*]] = call { <2 x i32>, <2 x i1> } @llvm.uadd.with.overflow.v2i32(<2 x i32> [[A:%.*]], <2 x i32> <i32 1, i32 1>)
; CHECK-NEXT: ret { <2 x i32>, <2 x i1> } [[ADD]]
;
%add = call { <2 x i32>, <2 x i1> } @llvm.uadd.with.overflow.v2i32(<2 x i32> %a, <2 x i32> <i32 1, i32 1>)
ret { <2 x i32>, <2 x i1> } %add
}
define i8 @uadd_sat_no_overflow(i8 %x) {
; CHECK-LABEL: @uadd_sat_no_overflow(
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[X:%.*]], 100
; CHECK-NEXT: br i1 [[CMP]], label [[TRAP:%.*]], label [[CONT:%.*]]
; CHECK: trap:
; CHECK-NEXT: call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: cont:
; CHECK-NEXT: [[RES1:%.*]] = add nuw i8 [[X]], 100
; CHECK-NEXT: ret i8 [[RES1]]
;
%cmp = icmp ugt i8 %x, 100
br i1 %cmp, label %trap, label %cont
trap:
call void @llvm.trap()
unreachable
cont:
%res = call i8 @llvm.uadd.sat.i8(i8 %x, i8 100)
ret i8 %res
}
define i8 @sadd_sat_no_overflow(i8 %x) {
; CHECK-LABEL: @sadd_sat_no_overflow(
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[X:%.*]], 100
; CHECK-NEXT: br i1 [[CMP]], label [[TRAP:%.*]], label [[CONT:%.*]]
; CHECK: trap:
; CHECK-NEXT: call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: cont:
; CHECK-NEXT: [[RES1:%.*]] = add nsw i8 [[X]], 20
; CHECK-NEXT: ret i8 [[RES1]]
;
%cmp = icmp sgt i8 %x, 100
br i1 %cmp, label %trap, label %cont
trap:
call void @llvm.trap()
unreachable
cont:
%res = call i8 @llvm.sadd.sat.i8(i8 %x, i8 20)
ret i8 %res
}
define i8 @usub_sat_no_overflow(i8 %x) {
; CHECK-LABEL: @usub_sat_no_overflow(
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[X:%.*]], 100
; CHECK-NEXT: br i1 [[CMP]], label [[TRAP:%.*]], label [[CONT:%.*]]
; CHECK: trap:
; CHECK-NEXT: call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: cont:
; CHECK-NEXT: [[RES1:%.*]] = sub nuw i8 [[X]], 100
; CHECK-NEXT: ret i8 [[RES1]]
;
%cmp = icmp ult i8 %x, 100
br i1 %cmp, label %trap, label %cont
trap:
call void @llvm.trap()
unreachable
cont:
%res = call i8 @llvm.usub.sat.i8(i8 %x, i8 100)
ret i8 %res
}
define i8 @ssub_sat_no_overflow(i8 %x) {
; CHECK-LABEL: @ssub_sat_no_overflow(
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], -100
; CHECK-NEXT: br i1 [[CMP]], label [[TRAP:%.*]], label [[CONT:%.*]]
; CHECK: trap:
; CHECK-NEXT: call void @llvm.trap()
; CHECK-NEXT: unreachable
; CHECK: cont:
; CHECK-NEXT: [[RES1:%.*]] = sub nsw i8 [[X]], 20
; CHECK-NEXT: ret i8 [[RES1]]
;
%cmp = icmp slt i8 %x, -100
br i1 %cmp, label %trap, label %cont
trap:
call void @llvm.trap()
unreachable
cont:
%res = call i8 @llvm.ssub.sat.i8(i8 %x, i8 20)
ret i8 %res
}
define <2 x i8> @uadd_sat_vec(<2 x i8> %a) {
; CHECK-LABEL: @uadd_sat_vec(
; CHECK-NEXT: [[ADD:%.*]] = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> [[A:%.*]], <2 x i8> <i8 1, i8 1>)
; CHECK-NEXT: ret <2 x i8> [[ADD]]
;
%add = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %a, <2 x i8> <i8 1, i8 1>)
ret <2 x i8> %add
}
; In the following tests, we should first simplify a with.overflow intrinsic
; to a simple arithmetic operation and insertvalue, but also simplify the
; subsequent comparison that is based on it.
define i1 @sadd_and_cmp(i32 %x, i32 %y) #0 {
; CHECK-LABEL: @sadd_and_cmp(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[X_OFFSET:%.*]] = add i32 [[X:%.*]], 9
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[X_OFFSET]], 19
; CHECK-NEXT: br i1 [[CMP1]], label [[CONT1:%.*]], label [[OUT:%.*]]
; CHECK: cont1:
; CHECK-NEXT: [[Y_OFFSET:%.*]] = add i32 [[Y:%.*]], 9
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[Y_OFFSET]], 19
; CHECK-NEXT: br i1 [[CMP2]], label [[CONT2:%.*]], label [[OUT]]
; CHECK: cont2:
; CHECK-NEXT: [[RES1:%.*]] = add nsw i32 [[X]], [[Y]]
; CHECK-NEXT: [[TMP0:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[RES1]], 0
; CHECK-NEXT: [[ADD:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0
; CHECK-NEXT: br label [[CONT3:%.*]]
; CHECK: cont3:
; CHECK-NEXT: br label [[OUT]]
; CHECK: out:
; CHECK-NEXT: ret i1 true
;
entry:
%x.offset = add i32 %x, 9
%cmp1 = icmp ult i32 %x.offset, 19
br i1 %cmp1, label %cont1, label %out
cont1:
%y.offset = add i32 %y, 9
%cmp2 = icmp ult i32 %y.offset, 19
br i1 %cmp2, label %cont2, label %out
cont2:
; x = [-9,10), y = [-9,10)
%res = tail call { i32, i1 } @llvm.sadd.with.overflow.i32(i32 %x, i32 %y)
%add = extractvalue { i32, i1 } %res, 0
br label %cont3
cont3:
; add = [-18,19)
%cmp3 = icmp slt i32 %add, 19
br label %out
out:
%ret = phi i1 [ true, %entry], [ true, %cont1 ], [ %cmp3, %cont3 ]
ret i1 %ret
}
define i1 @uadd_and_cmp(i32 %x, i32 %y) #0 {
; CHECK-LABEL: @uadd_and_cmp(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[X:%.*]], 10
; CHECK-NEXT: br i1 [[CMP1]], label [[CONT1:%.*]], label [[OUT:%.*]]
; CHECK: cont1:
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[Y:%.*]], 10
; CHECK-NEXT: br i1 [[CMP2]], label [[CONT2:%.*]], label [[OUT]]
; CHECK: cont2:
; CHECK-NEXT: [[RES1:%.*]] = add nuw i32 [[X]], [[Y]]
; CHECK-NEXT: [[TMP0:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[RES1]], 0
; CHECK-NEXT: [[ADD:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0
; CHECK-NEXT: br label [[CONT3:%.*]]
; CHECK: cont3:
; CHECK-NEXT: br label [[OUT]]
; CHECK: out:
; CHECK-NEXT: ret i1 true
;
entry:
%cmp1 = icmp ult i32 %x, 10
br i1 %cmp1, label %cont1, label %out
cont1:
%cmp2 = icmp ult i32 %y, 10
br i1 %cmp2, label %cont2, label %out
cont2:
%res = tail call { i32, i1 } @llvm.uadd.with.overflow.i32(i32 %x, i32 %y)
%add = extractvalue { i32, i1 } %res, 0
br label %cont3
cont3:
%cmp3 = icmp ult i32 %add, 19
br label %out
out:
%ret = phi i1 [ true, %entry], [ true, %cont1 ], [ %cmp3, %cont3 ]
ret i1 %ret
}
define i1 @ssub_and_cmp(i32 %x, i32 %y) #0 {
; CHECK-LABEL: @ssub_and_cmp(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[X:%.*]], 10
; CHECK-NEXT: br i1 [[CMP1]], label [[CONT1:%.*]], label [[OUT:%.*]]
; CHECK: cont1:
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[Y:%.*]], 10
; CHECK-NEXT: br i1 [[CMP2]], label [[CONT2:%.*]], label [[OUT]]
; CHECK: cont2:
; CHECK-NEXT: [[OFFSET:%.*]] = add nuw nsw i32 [[X]], 9
; CHECK-NEXT: [[RES1:%.*]] = sub nsw i32 [[OFFSET]], [[Y]]
; CHECK-NEXT: [[TMP0:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[RES1]], 0
; CHECK-NEXT: [[SUB:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0
; CHECK-NEXT: br label [[CONT3:%.*]]
; CHECK: cont3:
; CHECK-NEXT: br label [[OUT]]
; CHECK: out:
; CHECK-NEXT: ret i1 true
;
entry:
%cmp1 = icmp ult i32 %x, 10
br i1 %cmp1, label %cont1, label %out
cont1:
%cmp2 = icmp ult i32 %y, 10
br i1 %cmp2, label %cont2, label %out
cont2:
%offset = add i32 %x, 9
; x = [0,10), y = [0,10), offset = [9,19)
%res = tail call { i32, i1 } @llvm.ssub.with.overflow.i32(i32 %offset, i32 %y)
%sub = extractvalue { i32, i1 } %res, 0
br label %cont3
cont3:
%cmp3 = icmp ult i32 %sub, 19
br label %out
out:
%ret = phi i1 [ true, %entry], [ true, %cont1 ], [ %cmp3, %cont3 ]
ret i1 %ret
}
define i1 @usub_and_cmp(i32 %x, i32 %y) #0 {
; CHECK-LABEL: @usub_and_cmp(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[X:%.*]], 10
; CHECK-NEXT: br i1 [[CMP1]], label [[CONT1:%.*]], label [[OUT:%.*]]
; CHECK: cont1:
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[Y:%.*]], 10
; CHECK-NEXT: br i1 [[CMP2]], label [[CONT2:%.*]], label [[OUT]]
; CHECK: cont2:
; CHECK-NEXT: [[OFFSET:%.*]] = add nuw nsw i32 [[X]], 9
; CHECK-NEXT: [[RES1:%.*]] = sub nuw i32 [[OFFSET]], [[Y]]
; CHECK-NEXT: [[TMP0:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[RES1]], 0
; CHECK-NEXT: [[SUB:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0
; CHECK-NEXT: br label [[CONT3:%.*]]
; CHECK: cont3:
; CHECK-NEXT: br label [[OUT]]
; CHECK: out:
; CHECK-NEXT: ret i1 true
;
entry:
%cmp1 = icmp ult i32 %x, 10
br i1 %cmp1, label %cont1, label %out
cont1:
%cmp2 = icmp ult i32 %y, 10
br i1 %cmp2, label %cont2, label %out
cont2:
%offset = add i32 %x, 9
; x = [0,10), y = [0,10), offset = [9,19)
%res = tail call { i32, i1 } @llvm.usub.with.overflow.i32(i32 %offset, i32 %y)
%sub = extractvalue { i32, i1 } %res, 0
br label %cont3
cont3:
%cmp3 = icmp ult i32 %sub, 19
br label %out
out:
%ret = phi i1 [ true, %entry], [ true, %cont1 ], [ %cmp3, %cont3 ]
ret i1 %ret
}
define i1 @smul_and_cmp(i32 %x, i32 %y) #0 {
; CHECK-LABEL: @smul_and_cmp(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[X_OFFSET:%.*]] = add i32 [[X:%.*]], 9
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[X_OFFSET]], 19
; CHECK-NEXT: br i1 [[CMP1]], label [[CONT1:%.*]], label [[OUT:%.*]]
; CHECK: cont1:
; CHECK-NEXT: [[Y_OFFSET:%.*]] = add i32 [[Y:%.*]], 9
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[Y_OFFSET]], 19
; CHECK-NEXT: br i1 [[CMP2]], label [[CONT2:%.*]], label [[OUT]]
; CHECK: cont2:
; CHECK-NEXT: [[RES1:%.*]] = mul nsw i32 [[X]], [[Y]]
; CHECK-NEXT: [[TMP0:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[RES1]], 0
; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0
; CHECK-NEXT: br label [[CONT3:%.*]]
; CHECK: cont3:
; CHECK-NEXT: [[CMP5:%.*]] = and i1 true, true
; CHECK-NEXT: br label [[OUT]]
; CHECK: out:
; CHECK-NEXT: ret i1 true
;
entry:
%x.offset = add i32 %x, 9
%cmp1 = icmp ult i32 %x.offset, 19
br i1 %cmp1, label %cont1, label %out
cont1:
%y.offset = add i32 %y, 9
%cmp2 = icmp ult i32 %y.offset, 19
br i1 %cmp2, label %cont2, label %out
cont2:
; x = [-9,10), y = [-9,10)
%res = tail call { i32, i1 } @llvm.smul.with.overflow.i32(i32 %x, i32 %y)
%mul = extractvalue { i32, i1 } %res, 0
br label %cont3
cont3:
%cmp3 = icmp sle i32 %mul, 81
%cmp4 = icmp sge i32 %mul, -81
%cmp5 = and i1 %cmp3, %cmp4
br label %out
out:
%ret = phi i1 [ true, %entry], [ true, %cont1 ], [ %cmp5, %cont3 ]
ret i1 %ret
}
define i1 @umul_and_cmp(i32 %x, i32 %y) #0 {
; CHECK-LABEL: @umul_and_cmp(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i32 [[X:%.*]], 100
; CHECK-NEXT: br i1 [[CMP1]], label [[CONT1:%.*]], label [[OUT:%.*]]
; CHECK: cont1:
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i32 [[Y:%.*]], 100
; CHECK-NEXT: br i1 [[CMP2]], label [[CONT2:%.*]], label [[OUT]]
; CHECK: cont2:
; CHECK-NEXT: [[RES1:%.*]] = mul nuw i32 [[X]], [[Y]]
; CHECK-NEXT: [[TMP0:%.*]] = insertvalue { i32, i1 } { i32 undef, i1 false }, i32 [[RES1]], 0
; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i32, i1 } [[TMP0]], 0
; CHECK-NEXT: br label [[CONT3:%.*]]
; CHECK: cont3:
; CHECK-NEXT: br label [[OUT]]
; CHECK: out:
; CHECK-NEXT: ret i1 true
;
entry:
%cmp1 = icmp ult i32 %x, 100
br i1 %cmp1, label %cont1, label %out
cont1:
%cmp2 = icmp ult i32 %y, 100
br i1 %cmp2, label %cont2, label %out
cont2:
%res = tail call { i32, i1 } @llvm.umul.with.overflow.i32(i32 %x, i32 %y)
%mul = extractvalue { i32, i1 } %res, 0
br label %cont3
cont3:
%cmp3 = icmp ule i32 %mul, 9801
br label %out
out:
%ret = phi i1 [ true, %entry], [ true, %cont1 ], [ %cmp3, %cont3 ]
ret i1 %ret
}