-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[InstSimplify] Simplify 'x u>= 1' to true when x is known non-zero #145204
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@llvm/pr-subscribers-llvm-transforms Author: Iris Shi (el-ev) ChangesThere is a common pattern where Godbolt Example: https://godbolt.org/z/zGzTTYe57 Full diff: https://github.com/llvm/llvm-project/pull/145204.diff 2 Files Affected:
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index d1ac8d9fbdfd1..cb1dae92faf92 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -2981,7 +2981,7 @@ static Value *simplifyICmpWithZero(CmpPredicate Pred, Value *LHS, Value *RHS,
}
static Value *simplifyICmpWithConstant(CmpPredicate Pred, Value *LHS,
- Value *RHS, const InstrInfoQuery &IIQ) {
+ Value *RHS, const SimplifyQuery &Q) {
Type *ITy = getCompareTy(RHS); // The return type.
Value *X;
@@ -3007,7 +3007,7 @@ static Value *simplifyICmpWithConstant(CmpPredicate Pred, Value *LHS,
return ConstantInt::getTrue(ITy);
ConstantRange LHS_CR =
- computeConstantRange(LHS, CmpInst::isSigned(Pred), IIQ.UseInstrInfo);
+ computeConstantRange(LHS, CmpInst::isSigned(Pred), Q.IIQ.UseInstrInfo);
if (!LHS_CR.isFullSet()) {
if (RHS_CR.contains(LHS_CR))
return ConstantInt::getTrue(ITy);
@@ -3018,13 +3018,16 @@ static Value *simplifyICmpWithConstant(CmpPredicate Pred, Value *LHS,
// (mul nuw/nsw X, MulC) != C --> true (if C is not a multiple of MulC)
// (mul nuw/nsw X, MulC) == C --> false (if C is not a multiple of MulC)
const APInt *MulC;
- if (IIQ.UseInstrInfo && ICmpInst::isEquality(Pred) &&
+ if (Q.IIQ.UseInstrInfo && ICmpInst::isEquality(Pred) &&
((match(LHS, m_NUWMul(m_Value(), m_APIntAllowPoison(MulC))) &&
*MulC != 0 && C->urem(*MulC) != 0) ||
(match(LHS, m_NSWMul(m_Value(), m_APIntAllowPoison(MulC))) &&
*MulC != 0 && C->srem(*MulC) != 0)))
return ConstantInt::get(ITy, Pred == ICmpInst::ICMP_NE);
+ if (Pred == ICmpInst::ICMP_UGE && C->isOne() && isKnownNonZero(LHS, Q))
+ return ConstantInt::getTrue(ITy);
+
return nullptr;
}
@@ -3776,7 +3779,7 @@ static Value *simplifyICmpInst(CmpPredicate Pred, Value *LHS, Value *RHS,
if (Value *V = simplifyICmpWithZero(Pred, LHS, RHS, Q))
return V;
- if (Value *V = simplifyICmpWithConstant(Pred, LHS, RHS, Q.IIQ))
+ if (Value *V = simplifyICmpWithConstant(Pred, LHS, RHS, Q))
return V;
// If both operands have range metadata, use the metadata
diff --git a/llvm/test/Transforms/InstSimplify/umax-1.ll b/llvm/test/Transforms/InstSimplify/umax-1.ll
new file mode 100644
index 0000000000000..77863acb02327
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/umax-1.ll
@@ -0,0 +1,120 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
+
+define i32 @known_non_zero_by_or(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @known_non_zero_by_or(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[X]], 0
+; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: [[VAL:%.*]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[VAL]]
+; CHECK: [[IF_ELSE]]:
+; CHECK-NEXT: ret i32 0
+;
+ %cond = icmp ne i32 %x, 0
+ br i1 %cond, label %if.then, label %if.else
+
+if.then:
+ %val = or i32 %x, %y
+ %max = call i32 @llvm.umax.i32(i32 %val, i32 1)
+ ret i32 %max
+
+if.else:
+ ret i32 0
+}
+
+define i32 @known_non_zero_by_mul(i32 %x) {
+; CHECK-LABEL: define i32 @known_non_zero_by_mul(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[X]], 0
+; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: [[NONZERO1:%.*]] = mul nuw i32 [[X]], 3
+; CHECK-NEXT: ret i32 [[NONZERO1]]
+; CHECK: [[IF_ELSE]]:
+; CHECK-NEXT: ret i32 0
+;
+ %cond = icmp ne i32 %x, 0
+ br i1 %cond, label %if.then, label %if.else
+
+if.then:
+ %nonzero = mul nuw i32 %x, 3
+ %max = call i32 @llvm.umax.i32(i32 %nonzero, i32 1)
+ ret i32 %max
+
+if.else:
+ ret i32 0
+}
+
+define i32 @known_non_zero_commute(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @known_non_zero_commute(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[X]], 0
+; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: [[VAL:%.*]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[VAL]]
+; CHECK: [[IF_ELSE]]:
+; CHECK-NEXT: ret i32 0
+;
+ %cond = icmp ne i32 %x, 0
+ br i1 %cond, label %if.then, label %if.else
+
+if.then:
+ %val = or i32 %x, %y
+ %max = call i32 @llvm.umax.i32(i32 1, i32 %val)
+ ret i32 %max
+
+if.else:
+ ret i32 0
+}
+
+; Negative
+define i32 @umax_ge_2(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @umax_ge_2(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[X]], 0
+; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: [[VAL:%.*]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[VAL]], i32 2)
+; CHECK-NEXT: ret i32 [[MAX]]
+; CHECK: [[IF_ELSE]]:
+; CHECK-NEXT: ret i32 0
+;
+ %cond = icmp ne i32 %x, 0
+ br i1 %cond, label %if.then, label %if.else
+
+if.then:
+ %val = or i32 %x, %y
+ %max = call i32 @llvm.umax.i32(i32 %val, i32 2)
+ ret i32 %max
+
+if.else:
+ ret i32 0
+}
+
+define i32 @unknown_by_and(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @unknown_by_and(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[X]], 0
+; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: [[VAL:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[VAL]], i32 1)
+; CHECK-NEXT: ret i32 [[MAX]]
+; CHECK: [[IF_ELSE]]:
+; CHECK-NEXT: ret i32 0
+;
+ %cond = icmp ne i32 %x, 0
+ br i1 %cond, label %if.then, label %if.else
+
+if.then:
+ %val = and i32 %x, %y
+ %max = call i32 @llvm.umax.i32(i32 %val, i32 1)
+ ret i32 %max
+
+if.else:
+ ret i32 0
+}
|
|
@llvm/pr-subscribers-llvm-analysis Author: Iris Shi (el-ev) ChangesThere is a common pattern where Godbolt Example: https://godbolt.org/z/zGzTTYe57 Full diff: https://github.com/llvm/llvm-project/pull/145204.diff 2 Files Affected:
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index d1ac8d9fbdfd1..cb1dae92faf92 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -2981,7 +2981,7 @@ static Value *simplifyICmpWithZero(CmpPredicate Pred, Value *LHS, Value *RHS,
}
static Value *simplifyICmpWithConstant(CmpPredicate Pred, Value *LHS,
- Value *RHS, const InstrInfoQuery &IIQ) {
+ Value *RHS, const SimplifyQuery &Q) {
Type *ITy = getCompareTy(RHS); // The return type.
Value *X;
@@ -3007,7 +3007,7 @@ static Value *simplifyICmpWithConstant(CmpPredicate Pred, Value *LHS,
return ConstantInt::getTrue(ITy);
ConstantRange LHS_CR =
- computeConstantRange(LHS, CmpInst::isSigned(Pred), IIQ.UseInstrInfo);
+ computeConstantRange(LHS, CmpInst::isSigned(Pred), Q.IIQ.UseInstrInfo);
if (!LHS_CR.isFullSet()) {
if (RHS_CR.contains(LHS_CR))
return ConstantInt::getTrue(ITy);
@@ -3018,13 +3018,16 @@ static Value *simplifyICmpWithConstant(CmpPredicate Pred, Value *LHS,
// (mul nuw/nsw X, MulC) != C --> true (if C is not a multiple of MulC)
// (mul nuw/nsw X, MulC) == C --> false (if C is not a multiple of MulC)
const APInt *MulC;
- if (IIQ.UseInstrInfo && ICmpInst::isEquality(Pred) &&
+ if (Q.IIQ.UseInstrInfo && ICmpInst::isEquality(Pred) &&
((match(LHS, m_NUWMul(m_Value(), m_APIntAllowPoison(MulC))) &&
*MulC != 0 && C->urem(*MulC) != 0) ||
(match(LHS, m_NSWMul(m_Value(), m_APIntAllowPoison(MulC))) &&
*MulC != 0 && C->srem(*MulC) != 0)))
return ConstantInt::get(ITy, Pred == ICmpInst::ICMP_NE);
+ if (Pred == ICmpInst::ICMP_UGE && C->isOne() && isKnownNonZero(LHS, Q))
+ return ConstantInt::getTrue(ITy);
+
return nullptr;
}
@@ -3776,7 +3779,7 @@ static Value *simplifyICmpInst(CmpPredicate Pred, Value *LHS, Value *RHS,
if (Value *V = simplifyICmpWithZero(Pred, LHS, RHS, Q))
return V;
- if (Value *V = simplifyICmpWithConstant(Pred, LHS, RHS, Q.IIQ))
+ if (Value *V = simplifyICmpWithConstant(Pred, LHS, RHS, Q))
return V;
// If both operands have range metadata, use the metadata
diff --git a/llvm/test/Transforms/InstSimplify/umax-1.ll b/llvm/test/Transforms/InstSimplify/umax-1.ll
new file mode 100644
index 0000000000000..77863acb02327
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/umax-1.ll
@@ -0,0 +1,120 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
+
+define i32 @known_non_zero_by_or(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @known_non_zero_by_or(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[X]], 0
+; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: [[VAL:%.*]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[VAL]]
+; CHECK: [[IF_ELSE]]:
+; CHECK-NEXT: ret i32 0
+;
+ %cond = icmp ne i32 %x, 0
+ br i1 %cond, label %if.then, label %if.else
+
+if.then:
+ %val = or i32 %x, %y
+ %max = call i32 @llvm.umax.i32(i32 %val, i32 1)
+ ret i32 %max
+
+if.else:
+ ret i32 0
+}
+
+define i32 @known_non_zero_by_mul(i32 %x) {
+; CHECK-LABEL: define i32 @known_non_zero_by_mul(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[X]], 0
+; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: [[NONZERO1:%.*]] = mul nuw i32 [[X]], 3
+; CHECK-NEXT: ret i32 [[NONZERO1]]
+; CHECK: [[IF_ELSE]]:
+; CHECK-NEXT: ret i32 0
+;
+ %cond = icmp ne i32 %x, 0
+ br i1 %cond, label %if.then, label %if.else
+
+if.then:
+ %nonzero = mul nuw i32 %x, 3
+ %max = call i32 @llvm.umax.i32(i32 %nonzero, i32 1)
+ ret i32 %max
+
+if.else:
+ ret i32 0
+}
+
+define i32 @known_non_zero_commute(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @known_non_zero_commute(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[X]], 0
+; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: [[VAL:%.*]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: ret i32 [[VAL]]
+; CHECK: [[IF_ELSE]]:
+; CHECK-NEXT: ret i32 0
+;
+ %cond = icmp ne i32 %x, 0
+ br i1 %cond, label %if.then, label %if.else
+
+if.then:
+ %val = or i32 %x, %y
+ %max = call i32 @llvm.umax.i32(i32 1, i32 %val)
+ ret i32 %max
+
+if.else:
+ ret i32 0
+}
+
+; Negative
+define i32 @umax_ge_2(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @umax_ge_2(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[X]], 0
+; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: [[VAL:%.*]] = or i32 [[X]], [[Y]]
+; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[VAL]], i32 2)
+; CHECK-NEXT: ret i32 [[MAX]]
+; CHECK: [[IF_ELSE]]:
+; CHECK-NEXT: ret i32 0
+;
+ %cond = icmp ne i32 %x, 0
+ br i1 %cond, label %if.then, label %if.else
+
+if.then:
+ %val = or i32 %x, %y
+ %max = call i32 @llvm.umax.i32(i32 %val, i32 2)
+ ret i32 %max
+
+if.else:
+ ret i32 0
+}
+
+define i32 @unknown_by_and(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @unknown_by_and(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[X]], 0
+; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+; CHECK: [[IF_THEN]]:
+; CHECK-NEXT: [[VAL:%.*]] = and i32 [[X]], [[Y]]
+; CHECK-NEXT: [[MAX:%.*]] = call i32 @llvm.umax.i32(i32 [[VAL]], i32 1)
+; CHECK-NEXT: ret i32 [[MAX]]
+; CHECK: [[IF_ELSE]]:
+; CHECK-NEXT: ret i32 0
+;
+ %cond = icmp ne i32 %x, 0
+ br i1 %cond, label %if.then, label %if.else
+
+if.then:
+ %val = and i32 %x, %y
+ %max = call i32 @llvm.umax.i32(i32 %val, i32 1)
+ ret i32 %max
+
+if.else:
+ ret i32 0
+}
|
dtcxzyw
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thank you!
There is a common pattern where
umax(x, 1)is generated in loop preheaders. When we can prove thatxis non-zero, such call could be eliminated.Godbolt Example: https://godbolt.org/z/zGzTTYe57
Bench: dtcxzyw/llvm-opt-benchmark#2484