[llvm] 49f8b05 - [InstCombine] fold icmp equality with sdiv and SMIN
Sanjay Patel via llvm-commits
llvm-commits at lists.llvm.org
Thu May 26 13:19:34 PDT 2022
Author: Sanjay Patel
Date: 2022-05-26T16:19:15-04:00
New Revision: 49f8b0513763c2621d8d872ec19a33cc7a00d4c8
URL: https://github.com/llvm/llvm-project/commit/49f8b0513763c2621d8d872ec19a33cc7a00d4c8
DIFF: https://github.com/llvm/llvm-project/commit/49f8b0513763c2621d8d872ec19a33cc7a00d4c8.diff
LOG: [InstCombine] fold icmp equality with sdiv and SMIN
This extends the fold from D126410 / 3952c905ef08
to allow for the only case where it works with signed
division:
https://alive2.llvm.org/ce/z/k7_ypu
(X s/ Y) == SMIN --> (X == SMIN) && (Y == 1)
(X s/ Y) != SMIN --> (X != SMIN) || (Y != 1)
This is another improvement based on #55695.
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
llvm/test/Transforms/InstCombine/icmp-div-constant.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index c64463da9a16..1df61f0624bc 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -2388,17 +2388,6 @@ Instruction *InstCombinerImpl::foldICmpUDivConstant(ICmpInst &Cmp,
Value *Y = UDiv->getOperand(1);
Type *Ty = UDiv->getType();
- // If the compare constant is bigger than UMAX/2 (negative), there's only one
- // pair of values that satisfies an equality check, so eliminate the division:
- // (X u/ Y) == C --> (X == C) && (Y == 1)
- // (X u/ Y) != C --> (X != C) || (Y != 1)
- if (Cmp.isEquality() && UDiv->hasOneUse() && C.isSignBitSet()) {
- Value *XBig = Builder.CreateICmp(Pred, X, ConstantInt::get(Ty, C));
- Value *YOne = Builder.CreateICmp(Pred, Y, ConstantInt::get(Ty, 1));
- auto Logic = Pred == ICmpInst::ICMP_EQ ? Instruction::And : Instruction::Or;
- return BinaryOperator::Create(Logic, XBig, YOne);
- }
-
const APInt *C2;
if (!match(X, m_APInt(C2)))
return nullptr;
@@ -2431,6 +2420,23 @@ Instruction *InstCombinerImpl::foldICmpDivConstant(ICmpInst &Cmp,
Value *X = Div->getOperand(0);
Value *Y = Div->getOperand(1);
Type *Ty = Div->getType();
+ bool DivIsSigned = Div->getOpcode() == Instruction::SDiv;
+
+ // If unsigned division and the compare constant is bigger than
+ // UMAX/2 (negative), there's only one pair of values that satisfies an
+ // equality check, so eliminate the division:
+ // (X u/ Y) == C --> (X == C) && (Y == 1)
+ // (X u/ Y) != C --> (X != C) || (Y != 1)
+ // Similarly, if signed division and the compare constant is exactly SMIN:
+ // (X s/ Y) == SMIN --> (X == SMIN) && (Y == 1)
+ // (X s/ Y) != SMIN --> (X != SMIN) || (Y != 1)
+ if (Cmp.isEquality() && Div->hasOneUse() && C.isSignBitSet() &&
+ (!DivIsSigned || C.isMinSignedValue())) {
+ Value *XBig = Builder.CreateICmp(Pred, X, ConstantInt::get(Ty, C));
+ Value *YOne = Builder.CreateICmp(Pred, Y, ConstantInt::get(Ty, 1));
+ auto Logic = Pred == ICmpInst::ICMP_EQ ? Instruction::And : Instruction::Or;
+ return BinaryOperator::Create(Logic, XBig, YOne);
+ }
// Fold: icmp pred ([us]div X, C2), C -> range test
// Fold this div into the comparison, producing a range check.
@@ -2450,7 +2456,6 @@ Instruction *InstCombinerImpl::foldICmpDivConstant(ICmpInst &Cmp,
// (x /u C2) <u C. Simply casting the operands and result won't
// work. :( The if statement below tests that condition and bails
// if it finds it.
- bool DivIsSigned = Div->getOpcode() == Instruction::SDiv;
if (!Cmp.isEquality() && DivIsSigned != Cmp.isSigned())
return nullptr;
diff --git a/llvm/test/Transforms/InstCombine/icmp-div-constant.ll b/llvm/test/Transforms/InstCombine/icmp-div-constant.ll
index 9d7f25fecfd2..9348af51f4ae 100644
--- a/llvm/test/Transforms/InstCombine/icmp-div-constant.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-div-constant.ll
@@ -287,8 +287,9 @@ define i1 @udiv_eq_umax_use(i32 %x, i32 %y) {
define i1 @sdiv_eq_smin(i8 %x, i8 %y) {
; CHECK-LABEL: @sdiv_eq_smin(
-; CHECK-NEXT: [[D:%.*]] = sdiv i8 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[D]], -128
+; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[X:%.*]], -128
+; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[Y:%.*]], 1
+; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[TMP2]]
; CHECK-NEXT: ret i1 [[R]]
;
%d = sdiv i8 %x, %y
@@ -298,8 +299,9 @@ define i1 @sdiv_eq_smin(i8 %x, i8 %y) {
define <2 x i1> @sdiv_ne_smin(<2 x i5> %x, <2 x i5> %y) {
; CHECK-LABEL: @sdiv_ne_smin(
-; CHECK-NEXT: [[D:%.*]] = sdiv <2 x i5> [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i5> [[D]], <i5 -16, i5 -16>
+; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <2 x i5> [[X:%.*]], <i5 -16, i5 -16>
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ne <2 x i5> [[Y:%.*]], <i5 1, i5 1>
+; CHECK-NEXT: [[R:%.*]] = or <2 x i1> [[TMP1]], [[TMP2]]
; CHECK-NEXT: ret <2 x i1> [[R]]
;
%d = sdiv <2 x i5> %x, %y
@@ -307,6 +309,8 @@ define <2 x i1> @sdiv_ne_smin(<2 x i5> %x, <2 x i5> %y) {
ret <2 x i1> %r
}
+; negative test - must be SMIN
+
define i1 @sdiv_eq_small(i8 %x, i8 %y) {
; CHECK-LABEL: @sdiv_eq_small(
; CHECK-NEXT: [[D:%.*]] = sdiv i8 [[X:%.*]], [[Y:%.*]]
@@ -318,6 +322,8 @@ define i1 @sdiv_eq_small(i8 %x, i8 %y) {
ret i1 %r
}
+; negative test - must be SMIN
+
define i1 @sdiv_ne_big(i8 %x, i8 %y) {
; CHECK-LABEL: @sdiv_ne_big(
; CHECK-NEXT: [[D:%.*]] = sdiv i8 [[X:%.*]], [[Y:%.*]]
@@ -329,6 +335,8 @@ define i1 @sdiv_ne_big(i8 %x, i8 %y) {
ret i1 %r
}
+; negative test - must be SMIN
+
define i1 @sdiv_eq_not_big(i8 %x, i8 %y) {
; CHECK-LABEL: @sdiv_eq_not_big(
; CHECK-NEXT: [[D:%.*]] = sdiv i8 [[X:%.*]], [[Y:%.*]]
@@ -340,6 +348,8 @@ define i1 @sdiv_eq_not_big(i8 %x, i8 %y) {
ret i1 %r
}
+; negative test - must be equality predicate
+
define i1 @sdiv_ult_smin(i8 %x, i8 %y) {
; CHECK-LABEL: @sdiv_ult_smin(
; CHECK-NEXT: [[D:%.*]] = sdiv i8 [[X:%.*]], [[Y:%.*]]
@@ -351,6 +361,8 @@ define i1 @sdiv_ult_smin(i8 %x, i8 %y) {
ret i1 %r
}
+; negative test - extra use
+
define i1 @sdiv_eq_smin_use(i32 %x, i32 %y) {
; CHECK-LABEL: @sdiv_eq_smin_use(
; CHECK-NEXT: [[D:%.*]] = sdiv i32 [[X:%.*]], [[Y:%.*]]
More information about the llvm-commits
mailing list