[llvm] 85b2893 - [SCCP] convert signed div/rem to unsigned for non-negative operands, 2nd try
Sanjay Patel via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 7 08:56:38 PDT 2022
Author: Sanjay Patel
Date: 2022-09-07T11:56:29-04:00
New Revision: 85b289377bff14790f402e5ea84bb24168a68fc6
URL: https://github.com/llvm/llvm-project/commit/85b289377bff14790f402e5ea84bb24168a68fc6
DIFF: https://github.com/llvm/llvm-project/commit/85b289377bff14790f402e5ea84bb24168a68fc6.diff
LOG: [SCCP] convert signed div/rem to unsigned for non-negative operands, 2nd try
The original commit ( fe1f3cfc2669 ) was reverted because it could
crash / assert when trying to fold a value that was replaced
by a constant. In that case, there might not be an entry for the
constant in the solver yet.
This version adds a check for that possibility along with tests to
exercise that pattern (they used to crash).
Original commit message:
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
Added:
llvm/test/Transforms/SCCP/divrem-crash.ll
Modified:
llvm/lib/Transforms/Scalar/SCCP.cpp
llvm/test/Transforms/PhaseOrdering/srem.ll
llvm/test/Transforms/SCCP/binaryops-range-special-cases.ll
llvm/test/Transforms/SCCP/divrem.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp
index cccf1abf0a9ac..63a58b2d62340 100644
--- a/llvm/lib/Transforms/Scalar/SCCP.cpp
+++ b/llvm/lib/Transforms/Scalar/SCCP.cpp
@@ -160,6 +160,12 @@ static bool replaceSignedInst(SCCPSolver &Solver,
Instruction &Inst) {
// Determine if a signed value is known to be >= 0.
auto isNonNegative = [&Solver](Value *V) {
+ // If this value was constant-folded, it may not have a solver entry.
+ // Handle integers. Otherwise, return false.
+ if (auto *C = dyn_cast<Constant>(V)) {
+ auto *CInt = dyn_cast<ConstantInt>(C);
+ return CInt && !CInt->isNegative();
+ }
const ValueLatticeElement &IV = Solver.getLatticeValueFor(V);
return IV.isConstantRange(/*UndefAllowed=*/false) &&
IV.getConstantRange().isAllNonNegative();
@@ -175,6 +181,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;
}
diff --git a/llvm/test/Transforms/PhaseOrdering/srem.ll b/llvm/test/Transforms/PhaseOrdering/srem.ll
index fd935c6f86861..26a719191f7c8 100644
--- a/llvm/test/Transforms/PhaseOrdering/srem.ll
+++ b/llvm/test/Transforms/PhaseOrdering/srem.ll
@@ -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
diff --git a/llvm/test/Transforms/SCCP/binaryops-range-special-cases.ll b/llvm/test/Transforms/SCCP/binaryops-range-special-cases.ll
index 985974515fdca..b0e97421cffb4 100644
--- a/llvm/test/Transforms/SCCP/binaryops-range-special-cases.ll
+++ b/llvm/test/Transforms/SCCP/binaryops-range-special-cases.ll
@@ -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
diff --git a/llvm/test/Transforms/SCCP/divrem-crash.ll b/llvm/test/Transforms/SCCP/divrem-crash.ll
new file mode 100644
index 0000000000000..e559e6e68bf41
--- /dev/null
+++ b/llvm/test/Transforms/SCCP/divrem-crash.ll
@@ -0,0 +1,24 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -passes=ipsccp -S < %s | FileCheck %s
+
+ at g = internal global i32 42, align 4
+
+define i32 @sdiv_const_undef() {
+; CHECK-LABEL: @sdiv_const_undef(
+; CHECK-NEXT: [[D:%.*]] = sdiv i32 42, poison
+; CHECK-NEXT: ret i32 [[D]]
+;
+ %i = load i32, ptr @g, align 4
+ %d = sdiv i32 %i, poison
+ ret i32 %d
+}
+
+define i32 @sdiv_undef_const() {
+; CHECK-LABEL: @sdiv_undef_const(
+; CHECK-NEXT: [[D:%.*]] = sdiv i32 poison, 42
+; CHECK-NEXT: ret i32 [[D]]
+;
+ %i = load i32, ptr @g, align 4
+ %d = sdiv i32 poison, %i
+ ret i32 %d
+}
diff --git a/llvm/test/Transforms/SCCP/divrem.ll b/llvm/test/Transforms/SCCP/divrem.ll
index 6b85238050f0b..b3b47750d7781 100644
--- a/llvm/test/Transforms/SCCP/divrem.ll
+++ b/llvm/test/Transforms/SCCP/divrem.ll
@@ -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]] ]
More information about the llvm-commits
mailing list