[SCCP] convert signed div/rem to unsigned for non-negative operands
This extends the transform added with D81756 to handle div/rem opcodes. For example: https://alive2.llvm.org/ce/z/cX6za6 This replicates part of what CVP already does, but the motivating example from issue #57472 demonstrates a phase ordering problem - we convert branches to select before CVP runs and miss the transform. Differential Revision: https://reviews.llvm.org/D133198
This commit is contained in:
@@ -175,6 +175,18 @@ static bool replaceSignedInst(SCCPSolver &Solver,
|
||||
NewInst = new ZExtInst(Op0, Inst.getType(), "", &Inst);
|
||||
break;
|
||||
}
|
||||
case Instruction::SDiv:
|
||||
case Instruction::SRem: {
|
||||
// If both operands are not negative, this is the same as udiv/urem.
|
||||
Value *Op0 = Inst.getOperand(0), *Op1 = Inst.getOperand(1);
|
||||
if (InsertedValues.count(Op0) || InsertedValues.count(Op1) ||
|
||||
!isNonNegative(Op0) || !isNonNegative(Op1))
|
||||
return false;
|
||||
auto NewOpcode = Inst.getOpcode() == Instruction::SDiv ? Instruction::UDiv
|
||||
: Instruction::URem;
|
||||
NewInst = BinaryOperator::Create(NewOpcode, Op0, Op1, "", &Inst);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3,13 +3,16 @@
|
||||
; RUN: opt -O2 -S < %s | FileCheck %s
|
||||
; RUN: opt -O3 -S < %s | FileCheck %s
|
||||
|
||||
; srem should be folded based on branch conditions
|
||||
; This can be done by IPSCCP or CVP.
|
||||
|
||||
define i32 @PR57472(i32 noundef %x) {
|
||||
; CHECK-LABEL: @PR57472(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], -1
|
||||
; CHECK-NEXT: [[REM:%.*]] = srem i32 [[X]], 16
|
||||
; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[REM]], i32 42
|
||||
; CHECK-NEXT: ret i32 [[COND]]
|
||||
; CHECK-NEXT: [[REM:%.*]] = and i32 [[X]], 15
|
||||
; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[CMP]], i32 [[REM]], i32 42
|
||||
; CHECK-NEXT: ret i32 [[SPEC_SELECT]]
|
||||
;
|
||||
entry:
|
||||
%x.addr = alloca i32, align 4
|
||||
|
||||
@@ -130,7 +130,7 @@ define void @srem_cmp_constants() {
|
||||
; CHECK-NEXT: call void @use(i1 false)
|
||||
; CHECK-NEXT: call void @use(i1 true)
|
||||
; CHECK-NEXT: call void @use(i1 false)
|
||||
; CHECK-NEXT: [[SREM_3:%.*]] = srem i16 12704, 0
|
||||
; CHECK-NEXT: [[SREM_3:%.*]] = urem i16 12704, 0
|
||||
; CHECK-NEXT: [[C_5:%.*]] = icmp eq i16 [[SREM_3]], 1
|
||||
; CHECK-NEXT: call void @use(i1 [[C_5]])
|
||||
; CHECK-NEXT: ret void
|
||||
|
||||
@@ -5,7 +5,7 @@ define i8 @sdiv_nonneg0_nonneg1(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @sdiv_nonneg0_nonneg1(
|
||||
; CHECK-NEXT: [[PX:%.*]] = and i8 [[X:%.*]], 127
|
||||
; CHECK-NEXT: [[PY:%.*]] = lshr i8 [[Y:%.*]], 1
|
||||
; CHECK-NEXT: [[R:%.*]] = sdiv i8 [[PX]], [[PY]]
|
||||
; CHECK-NEXT: [[R:%.*]] = udiv i8 [[PX]], [[PY]]
|
||||
; CHECK-NEXT: ret i8 [[R]]
|
||||
;
|
||||
%px = and i8 %x, 127
|
||||
@@ -17,7 +17,7 @@ define i8 @sdiv_nonneg0_nonneg1(i8 %x, i8 %y) {
|
||||
define i8 @sdiv_nonnegconst0_nonneg1(i7 %y) {
|
||||
; CHECK-LABEL: @sdiv_nonnegconst0_nonneg1(
|
||||
; CHECK-NEXT: [[PY:%.*]] = zext i7 [[Y:%.*]] to i8
|
||||
; CHECK-NEXT: [[R:%.*]] = sdiv i8 42, [[PY]]
|
||||
; CHECK-NEXT: [[R:%.*]] = udiv i8 42, [[PY]]
|
||||
; CHECK-NEXT: ret i8 [[R]]
|
||||
;
|
||||
%py = zext i7 %y to i8
|
||||
@@ -25,6 +25,8 @@ define i8 @sdiv_nonnegconst0_nonneg1(i7 %y) {
|
||||
ret i8 %r
|
||||
}
|
||||
|
||||
; TODO: This can be converted to udiv.
|
||||
|
||||
define i8 @sdiv_nonneg0_nonnegconst1(i8 %x) {
|
||||
; CHECK-LABEL: @sdiv_nonneg0_nonnegconst1(
|
||||
; CHECK-NEXT: [[PX:%.*]] = mul nsw i8 [[X:%.*]], [[X]]
|
||||
@@ -36,6 +38,8 @@ define i8 @sdiv_nonneg0_nonnegconst1(i8 %x) {
|
||||
ret i8 %r
|
||||
}
|
||||
|
||||
; negative test
|
||||
|
||||
define i8 @sdiv_unknown0_nonneg1(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @sdiv_unknown0_nonneg1(
|
||||
; CHECK-NEXT: [[PY:%.*]] = lshr i8 [[Y:%.*]], 1
|
||||
@@ -47,6 +51,8 @@ define i8 @sdiv_unknown0_nonneg1(i8 %x, i8 %y) {
|
||||
ret i8 %r
|
||||
}
|
||||
|
||||
; negative test
|
||||
|
||||
define i8 @sdiv_nonnegconst0_unknown1(i7 %y) {
|
||||
; CHECK-LABEL: @sdiv_nonnegconst0_unknown1(
|
||||
; CHECK-NEXT: [[SY:%.*]] = sext i7 [[Y:%.*]] to i8
|
||||
@@ -58,6 +64,8 @@ define i8 @sdiv_nonnegconst0_unknown1(i7 %y) {
|
||||
ret i8 %r
|
||||
}
|
||||
|
||||
; negative test - mul must be 'nsw' to be known non-negative
|
||||
|
||||
define i8 @sdiv_unknown0_nonnegconst1(i8 %x) {
|
||||
; CHECK-LABEL: @sdiv_unknown0_nonnegconst1(
|
||||
; CHECK-NEXT: [[SX:%.*]] = mul i8 [[X:%.*]], [[X]]
|
||||
@@ -73,7 +81,7 @@ define i8 @srem_nonneg0_nonneg1(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @srem_nonneg0_nonneg1(
|
||||
; CHECK-NEXT: [[PX:%.*]] = and i8 [[X:%.*]], 127
|
||||
; CHECK-NEXT: [[PY:%.*]] = lshr i8 [[Y:%.*]], 1
|
||||
; CHECK-NEXT: [[R:%.*]] = srem i8 [[PX]], [[PY]]
|
||||
; CHECK-NEXT: [[R:%.*]] = urem i8 [[PX]], [[PY]]
|
||||
; CHECK-NEXT: ret i8 [[R]]
|
||||
;
|
||||
%px = and i8 %x, 127
|
||||
@@ -85,7 +93,7 @@ define i8 @srem_nonneg0_nonneg1(i8 %x, i8 %y) {
|
||||
define i8 @srem_nonnegconst0_nonneg1(i8 %y) {
|
||||
; CHECK-LABEL: @srem_nonnegconst0_nonneg1(
|
||||
; CHECK-NEXT: [[PY:%.*]] = and i8 [[Y:%.*]], 127
|
||||
; CHECK-NEXT: [[R:%.*]] = srem i8 42, [[PY]]
|
||||
; CHECK-NEXT: [[R:%.*]] = urem i8 42, [[PY]]
|
||||
; CHECK-NEXT: ret i8 [[R]]
|
||||
;
|
||||
%py = and i8 %y, 127
|
||||
@@ -96,7 +104,7 @@ define i8 @srem_nonnegconst0_nonneg1(i8 %y) {
|
||||
define i8 @srem_nonneg0_nonnegconst1(i7 %x) {
|
||||
; CHECK-LABEL: @srem_nonneg0_nonnegconst1(
|
||||
; CHECK-NEXT: [[PX:%.*]] = zext i7 [[X:%.*]] to i8
|
||||
; CHECK-NEXT: [[R:%.*]] = srem i8 [[PX]], 42
|
||||
; CHECK-NEXT: [[R:%.*]] = urem i8 [[PX]], 42
|
||||
; CHECK-NEXT: ret i8 [[R]]
|
||||
;
|
||||
%px = zext i7 %x to i8
|
||||
@@ -104,6 +112,8 @@ define i8 @srem_nonneg0_nonnegconst1(i7 %x) {
|
||||
ret i8 %r
|
||||
}
|
||||
|
||||
; negative test
|
||||
|
||||
define i8 @srem_unknown0_nonneg1(i8 %x, i8 %y) {
|
||||
; CHECK-LABEL: @srem_unknown0_nonneg1(
|
||||
; CHECK-NEXT: [[PY:%.*]] = lshr i8 [[Y:%.*]], 1
|
||||
@@ -115,6 +125,8 @@ define i8 @srem_unknown0_nonneg1(i8 %x, i8 %y) {
|
||||
ret i8 %r
|
||||
}
|
||||
|
||||
; negative test
|
||||
|
||||
define i8 @srem_nonnegconst0_unknown1(i7 %y) {
|
||||
; CHECK-LABEL: @srem_nonnegconst0_unknown1(
|
||||
; CHECK-NEXT: [[SY:%.*]] = sext i7 [[Y:%.*]] to i8
|
||||
@@ -126,6 +138,8 @@ define i8 @srem_nonnegconst0_unknown1(i7 %y) {
|
||||
ret i8 %r
|
||||
}
|
||||
|
||||
; negative test - mul must be 'nsw' to be known non-negative
|
||||
|
||||
define i8 @srem_unknown0_nonnegconst1(i8 %x) {
|
||||
; CHECK-LABEL: @srem_unknown0_nonnegconst1(
|
||||
; CHECK-NEXT: [[SX:%.*]] = mul i8 [[X:%.*]], [[X]]
|
||||
@@ -137,13 +151,15 @@ define i8 @srem_unknown0_nonnegconst1(i8 %x) {
|
||||
ret i8 %r
|
||||
}
|
||||
|
||||
; x is known non-negative in t block
|
||||
|
||||
define i32 @PR57472(i32 %x) {
|
||||
; CHECK-LABEL: @PR57472(
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[X:%.*]], 0
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]]
|
||||
; CHECK: t:
|
||||
; CHECK-NEXT: [[REM:%.*]] = srem i32 [[X]], 16
|
||||
; CHECK-NEXT: [[REM:%.*]] = urem i32 [[X]], 16
|
||||
; CHECK-NEXT: br label [[EXIT:%.*]]
|
||||
; CHECK: f:
|
||||
; CHECK-NEXT: br label [[EXIT]]
|
||||
@@ -167,6 +183,8 @@ exit:
|
||||
ret i32 %cond
|
||||
}
|
||||
|
||||
; x is known non-negative in f block
|
||||
|
||||
define i32 @PR57472_alt(i32 %x) {
|
||||
; CHECK-LABEL: @PR57472_alt(
|
||||
; CHECK-NEXT: entry:
|
||||
@@ -175,7 +193,7 @@ define i32 @PR57472_alt(i32 %x) {
|
||||
; CHECK: t:
|
||||
; CHECK-NEXT: br label [[EXIT:%.*]]
|
||||
; CHECK: f:
|
||||
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 16, [[X]]
|
||||
; CHECK-NEXT: [[DIV:%.*]] = udiv i32 16, [[X]]
|
||||
; CHECK-NEXT: br label [[EXIT]]
|
||||
; CHECK: exit:
|
||||
; CHECK-NEXT: [[COND:%.*]] = phi i32 [ -42, [[T]] ], [ [[DIV]], [[F]] ]
|
||||
|
||||
Reference in New Issue
Block a user