-
Notifications
You must be signed in to change notification settings - Fork 10.8k
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
[InstCombine] Fold icmp in select to smin #87157
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-llvm-transforms Author: Krishna Narayanan (Krishna-13-cyber) ChangesIntends to solve #85844 Full diff: https://github.com/llvm/llvm-project/pull/87157.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 9ab2bd8f70aa15..4e58ba5f01df1c 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1687,6 +1687,25 @@ static Value *foldSelectInstWithICmpConst(SelectInst &SI, ICmpInst *ICI,
return nullptr;
}
+static Value *foldSelectInstWithICmpOr(SelectInst &SI, ICmpInst *ICI,
+ InstCombiner::BuilderTy &Builder) {
+ /* a > -1 ? 1 : (a | 3) --> smin(1, a | 3) */
+ Type *Ty = SI.getType();
+ Value *TVal = SI.getTrueValue();
+ Value *FVal = SI.getFalseValue();
+ Constant *One = ConstantInt::get(Ty, 1);
+ CmpInst::Predicate Pred = ICI->getPredicate();
+ Value *A = ICI->getOperand(0);
+ const APInt *Cmp;
+
+ if (!match(TVal, m_One()) || !match(FVal, m_Or(m_Value(A), m_SpecificInt(3))))
+ return nullptr;
+
+ if (Pred == ICmpInst::ICMP_SGT && *Cmp == -1 && match(TVal, m_One()) &&
+ match(FVal, m_Or(m_Value(A), m_SpecificInt(3))))
+ return Builder.CreateBinaryIntrinsic(Intrinsic::smin, One, FVal);
+}
+
/// Visit a SelectInst that has an ICmpInst as its first operand.
Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
ICmpInst *ICI) {
@@ -1700,6 +1719,9 @@ Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI,
if (Value *V = foldSelectInstWithICmpConst(SI, ICI, Builder))
return replaceInstUsesWith(SI, V);
+ if (Value *V = foldSelectInstWithICmpOr(SI, ICI, Builder))
+ return replaceInstUsesWith(SI, V);
+
if (Value *V = canonicalizeClampLike(SI, *ICI, Builder))
return replaceInstUsesWith(SI, V);
diff --git a/llvm/test/Transforms/InstCombine/icmp-select.ll b/llvm/test/Transforms/InstCombine/icmp-select.ll
index 59d2a1b165c0f8..80341278b58f3a 100644
--- a/llvm/test/Transforms/InstCombine/icmp-select.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-select.ll
@@ -628,3 +628,16 @@ define i1 @icmp_slt_select(i1 %cond, i32 %a, i32 %b) {
%res = icmp slt i32 %lhs, %rhs
ret i1 %res
}
+
+define i8 @icmp_slt_select_or(i8 %inl) {
+; CHECK-LABEL: @icmp_slt_select_or(
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[INL:%.*]], 3
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[INL]], -1
+; CHECK-NEXT: [[S:%.*]] = select i1 [[CMP]], i8 1, i8 [[OR]]
+; CHECK-NEXT: ret i8 [[S]]
+;
+ %or = or i8 %inl, 3
+ %cmp = icmp sgt i8 %inl, -1
+ %s = select i1 %cmp, i8 1, i8 %or
+ ret i8 %s
+}
|
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.
The issue is a specifc case, you need to provide a generalized pattern at least. See also https://llvm.org/docs/InstCombineContributorGuide.html#generalization
Got it, I will make the required changes. |
Your proofs are incomplete, you only prove the specific constants you chose (and in fact your code does not hold for |
InstCombiner::BuilderTy &Builder) { | ||
|
||
// a > -1 ? 1 : (a | value) --> smin(1, a | value) | ||
// a >= 0 ? 1 : (a | value) --> smin(1, a | value) |
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.
You don't need to handle a >= 0
, it is canonicalized to a > -1
.
Constant *Zero = Constant::getNullValue(Ty); | ||
CmpInst::Predicate Pred = ICI->getPredicate(); | ||
|
||
if (!match(B, m_APIntAllowUndef(Cmp))) |
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.
If you are going to allow undef, please add a vector test with some undef elements.
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.
But either way, this should just be if(!match(B, m_AllOnes())
|
||
// Swap TVal, FVal for Inverse | ||
if (Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SLE) | ||
std::swap(TVal, FVal); |
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.
Think you are missing a Pred = ICmpInst::getInversePred(Pred)
here too.
return nullptr; | ||
|
||
if (((Pred == ICmpInst::ICMP_SGT && *Cmp == -1) || | ||
(Pred == ICmpInst::ICMP_SGE && *Cmp == 0))) |
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.
As mentioned above, no need for the SGE
/ *Cmp==0
case.
You need it for the swapped slt
case.
static Value *foldSelectInstWithICmpOr(SelectInst &SI, ICmpInst *ICI, | ||
InstCombiner::BuilderTy &Builder) { | ||
|
||
// a > -1 ? 1 : (a | value) --> smin(1, a | value) |
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.
comment should indicate value
must be strictly positive.
if (match(TVal, m_Zero())) | ||
return Builder.CreateBinaryIntrinsic(Intrinsic::smin, Zero, FVal); | ||
if (match(TVal, m_AllOnes())) | ||
return Builder.CreateBinaryIntrinsic(Intrinsic::smin, NegOne, FVal); |
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.
This could be simplified to:
if(match(TVal, m_One()) || match(TVal, m_AllOnes()) || match(TVal, m_Zero())) {
return Builder.Create...(smin, TVal, FVal);
}
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.
Also your comment / proofs only seem to cover the TVal == 1
case, can you please update them to cover the other two cases.
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.
I think the same link has tests with TVal for -1, 1 and 0. I will check again and update that accordingly.
!match(FVal, m_Or(m_Value(A), m_StrictlyPositive()))) | ||
return nullptr; | ||
|
||
if (((Pred == ICmpInst::ICMP_SGT && *Cmp == -1) || |
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.
Cmp->isAllOnes()
and Cmp->isZero()
Thanks a lot for the review, yes I did refer the guide, incorporated these proofs as well. |
!(match(FVal, m_Or(m_Value(A), m_Value(C))))) | ||
return nullptr; | ||
|
||
if (!match(C, m_StrictlyPositive())) |
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.
Whats the point if using C
as an intermediate here?
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.
Yes, there was no specific reason/point to do this.
if (....!(match(FVal, m_Or(m_Value(A), m_Value(C)))))
return nullptr;
if (!match(C, m_StrictlyPositive()))
return nullptr;
if (...... !(match(FVal, m_Or(m_Value(A), m_StrictlyPositive()))))
Either of them failed to pass the llvm.assume test cases as the expression don't fold, so tried using the earlier approach.
As this fold is only applicable for positive values, we cannot match any other values other than this as it would lead to invalid transform.
Not sure what constraint or needful I am missing out to handle these generic testcases, would need some assistance in this.
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.
m_StrictlyPositive
matches an constant that is positive. To check certain bits in a non-constant value use the ValueTracking
interface. In this case you would use isKnownStrictlyPositive
.
Intends to solve #85844
Alive2 Proofs: https://alive2.llvm.org/ce/z/FRNgbc