-
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
[ValueTracking] Infer relationship for the select with ICmp #66668
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-llvm-transforms @llvm/pr-subscribers-llvm-analysis Changesx-y+1 is positive when x > y, so abs (x-y+1) --> x-y+1 Fixes #54735 Full diff: https://github.com/llvm/llvm-project/pull/66668.diff 2 Files Affected:
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 5fe0d53c313d40e..ecb261716cb71fb 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -4547,6 +4547,20 @@ static Value *simplifySelectWithICmpEq(Value *CmpLHS, Value *CmpRHS,
return nullptr;
}
+/// Return nullptr if the comparison relationship of X and Y can't be inferred.
+static Value *simplifySelectWithICmpKnownRelation(ICmpInst::Predicate Pred,
+ Value *CmpLHS, Value *CmpRHS,
+ Value *TrueVal,
+ Value *FalseVal,
+ const SimplifyQuery &Q) {
+ if (std::optional<bool> Flag =
+ isImpliedByDomCondition(Pred, CmpLHS, CmpRHS, Q.CxtI, Q.DL)) {
+ if (Flag)
+ return *Flag ? TrueVal : FalseVal;
+ }
+ return nullptr;
+}
+
/// Try to simplify a select instruction when its condition operand is an
/// integer comparison.
static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
@@ -4669,6 +4683,17 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal,
}
}
+ if (Pred == ICmpInst::ICMP_SLT) {
+ Value *X;
+ Value *Y;
+ const APInt *C;
+ // x-y+1 is positive when x >= y or non-positive when x < y
+ if (match(CmpLHS, m_NSWSub(m_Value(X), m_Value(Y))) &&
+ match(CmpRHS, m_AllOnes()))
+ return simplifySelectWithICmpKnownRelation(ICmpInst::ICMP_SLT, X, Y,
+ TrueVal, FalseVal, Q);
+ }
+
return nullptr;
}
diff --git a/llvm/test/Transforms/InstSimplify/select-icmp.ll b/llvm/test/Transforms/InstSimplify/select-icmp.ll
new file mode 100755
index 000000000000000..1271941565d9dc3
--- /dev/null
+++ b/llvm/test/Transforms/InstSimplify/select-icmp.ll
@@ -0,0 +1,33 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
+
+; https://alive2.llvm.org/ce/z/zKX64J
+define i32 @pr54735(i32 noundef %x, i32 noundef %y) {
+; CHECK-LABEL: @pr54735(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]]
+; CHECK: cond.true:
+; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X]], [[Y]]
+; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[SUB]], 1
+; CHECK-NEXT: br label [[COND_END]]
+; CHECK: cond.end:
+; CHECK-NEXT: [[COND:%.*]] = phi i32 [ [[ADD]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+entry:
+ %cmp = icmp sgt i32 %x, %y
+ br i1 %cmp, label %cond.true, label %cond.end
+
+cond.true: ; preds = %entry
+ %sub = sub nsw i32 %x, %y
+ %add = add nsw i32 %sub, 1
+ %neg = xor i32 %sub, -1 ; sub nsw i32 0, %add
+ %abscond = icmp slt i32 %sub, -1
+ %abs = select i1 %abscond, i32 %neg, i32 %add
+ br label %cond.end
+
+cond.end: ; preds = %entry, %cond.true
+ %cond = phi i32 [ %abs, %cond.true ], [ 0, %entry ]
+ ret i32 %cond
+}
|
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 believe this needs to be handled in isImpliedCondition. There is already existing code that will simplify implications from dominating conditions.
Though really, this seems like something that ConstraintElimination should handle, not InstSimplify.
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.
Please add an alive2 proof to the patch description. This should also needs additional tests (preferably more minimal than the example you added), e.g. that this does not fold without nsw, wrong constant, etc.
Thanks, Added alive2 proof link and 2 extra negative test cases. |
ping ? |
✅ With the latest revision this PR passed the C/C++ code formatter. |
revert the change for |
ping ? |
llvm/lib/Analysis/ValueTracking.cpp
Outdated
@@ -8294,6 +8294,17 @@ static std::optional<bool> isImpliedCondICmps(const ICmpInst *LHS, | |||
if (areMatchingOperands(L0, L1, R0, R1, AreSwappedOps)) | |||
return isImpliedCondMatchingOperands(LPred, RPred, AreSwappedOps); | |||
|
|||
if (LPred == ICmpInst::ICMP_SGT) { |
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.
Should also handle the less-than variant no?
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.
hi @goldsteinn
I reverted the change for less-than because the commit #66668 (review), so I think it may be addressed with some other method.
If you don't object, I think it is fine to keep this PR to fix the issue in the comment link.
rebase to fix the conflict to commit 460faa0 |
ping ? |
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 implementation LGTM. But it would be good to support more predicates (slt/ult).
Please wait for additional approval from other reviewers.
|
hi @nikic, would you help to give some suggestion on this PR ? |
ping ? |
If there's no objection, I'll take a try for this commit in the next week? |
Ping @nikic @goldsteinn |
if (match(R1, m_NonPositive()) && | ||
areMatchingOperands(L0, L1, X, Y, AreSwappedOps) && | ||
isImpliedCondMatchingOperands(LPred, RPred, AreSwappedOps) == false) | ||
return false; |
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 could handle SLT
/SLE
/ULT
/ULE
as true
here no?
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.
hi @dtcxzyw, @goldsteinn
I add the addressing for SLT/SLE/ULT/ULE now, thanks
5aa207b
to
8a732dc
Compare
if (match(R1, m_NonNegative()) && (L0 == X && L1 == Y) && | ||
isImpliedCondMatchingOperands(LPred, RPred) == true) | ||
return true; | ||
} |
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.
Both here and above, instead of m_Value(X)/m_Value(Y), how about m_Specific(L0)/m_Specific(L1)?
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.
Apply your comment, thanks
llvm/lib/Analysis/ValueTracking.cpp
Outdated
if (((LPred == ICmpInst::ICMP_SGT || LPred == ICmpInst::ICMP_SGE) && | ||
match(R0, m_NSWSub(m_Value(X), m_Value(Y)))) || | ||
((LPred == ICmpInst::ICMP_UGT || LPred == ICmpInst::ICMP_UGE) && | ||
match(R0, m_NUWSub(m_Value(X), m_Value(Y))))) { |
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.
Here and below, don't think you need nuw
for the sub. Its implied by LPred.
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.
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.
Actually I misspoke, but I don't think your proofs are correct. The nuw
on the sub nuw i8 0, %add
forces %add
to be 0. Likewise the sub nuw i8 %sub, %c
essentially forces the condition you want, not the dominating predicates.
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.
Thanks @goldsteinn , If this only valid for 0 with nuw, so the transformation of unsigned should be deleted (only keep it for signed types) ? or do you have other suggestion ?
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.
Yeah, unsigned doesn't make sense here. The is really saying "X - Y must be positive if X >= Y and no overflow". That only really makes sense in the context of signed comparison.
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.
Thanks for the confirmation, and delete the parts of unsigned.
ret i8 %abs | ||
|
||
cond.end: ; preds = %entry, %cond.true | ||
ret i8 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.
You can drop the unsigned tests.
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.
Apply your comments, thanks @goldsteinn
x-y+1 is positive when x > y, so abs (x-y+1) --> x-y+1 Fixes llvm#54735
x -nsw y < -C is false when x > y and C >= 0 Alive2 proof for sgt, sge : https://alive2.llvm.org/ce/z/tupvfi Note: It only really makes sense in the context of signed comparison for "X - Y must be positive if X >= Y and no overflow". Fixes llvm#54735
if (match(R1, m_NonPositive()) && | ||
isImpliedCondMatchingOperands(LPred, RPred) == false) | ||
return false; | ||
} |
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.
Is this right for sge
if C == 0
? Your proofs checkout but afaict its b.c your proof is using X != -X
to handle the false case which has problems with this case...
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.
Does the link https://alive2.llvm.org/ce/z/N4uvTh proof it is valid for sge with C == 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.
I made a mistake think this is okay.
LGTM. Please wait for an additional approval |
|
x -nsw y < C is false when x > y and C <= 0
Alive2 proof for sgt, sge, ugt, uge : https://alive2.llvm.org/ce/z/tupvfi
Fixes #54735