Skip to content
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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

vfdff
Copy link
Contributor

@vfdff vfdff commented Sep 18, 2023

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

@llvmbot
Copy link
Collaborator

llvmbot commented Sep 18, 2023

@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-llvm-analysis

Changes

x-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:

  • (modified) llvm/lib/Analysis/InstructionSimplify.cpp (+25)
  • (added) llvm/test/Transforms/InstSimplify/select-icmp.ll (+33)
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
+}

Copy link
Contributor

@nikic nikic left a 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.

Copy link
Contributor

@nikic nikic left a 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.

llvm/lib/Analysis/ValueTracking.cpp Outdated Show resolved Hide resolved
@vfdff
Copy link
Contributor Author

vfdff commented Sep 21, 2023

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.

@vfdff
Copy link
Contributor Author

vfdff commented Sep 28, 2023

ping ?

@vfdff vfdff requested review from nikic and goldsteinn October 7, 2023 16:53
@vfdff vfdff requested a review from dtcxzyw October 15, 2023 09:04
llvm/lib/Analysis/ValueTracking.cpp Outdated Show resolved Hide resolved
@github-actions
Copy link

github-actions bot commented Oct 17, 2023

✅ With the latest revision this PR passed the C/C++ code formatter.

@vfdff
Copy link
Contributor Author

vfdff commented Nov 4, 2023

revert the change for x -nsw y <= -1 <==> x < y because sle -1 will get canonicalized to slt 0, so should consider other way to address that.

@vfdff vfdff requested a review from dtcxzyw November 7, 2023 03:19
@vfdff
Copy link
Contributor Author

vfdff commented Nov 22, 2023

ping ?

@@ -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) {
Copy link
Contributor

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?

Copy link
Contributor Author

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.

@vfdff
Copy link
Contributor Author

vfdff commented Dec 5, 2023

rebase to fix the conflict to commit 460faa0

@vfdff
Copy link
Contributor Author

vfdff commented Dec 8, 2023

ping ?

dtcxzyw added a commit to dtcxzyw/llvm-opt-benchmark that referenced this pull request Dec 29, 2023
Copy link
Member

@dtcxzyw dtcxzyw left a 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.

llvm/lib/Analysis/ValueTracking.cpp Outdated Show resolved Hide resolved
@vfdff
Copy link
Contributor Author

vfdff commented Dec 30, 2023

The implementation LGTM. But it would be good to support more predicates (slt/ult).

Please wait for additional approval from other reviewers.
Thanks for your notification, I'll follow to address slt/ult after this PR is accepted.

@vfdff
Copy link
Contributor Author

vfdff commented Dec 30, 2023

hi @nikic, would you help to give some suggestion on this PR ?

@vfdff
Copy link
Contributor Author

vfdff commented Feb 4, 2024

ping ?

@vfdff
Copy link
Contributor Author

vfdff commented Mar 9, 2024

If there's no objection, I'll take a try for this commit in the next week?

dtcxzyw added a commit to dtcxzyw/llvm-opt-benchmark that referenced this pull request Mar 9, 2024
@dtcxzyw
Copy link
Member

dtcxzyw commented Mar 9, 2024

Ping @nikic @goldsteinn

if (match(R1, m_NonPositive()) &&
areMatchingOperands(L0, L1, X, Y, AreSwappedOps) &&
isImpliedCondMatchingOperands(LPred, RPred, AreSwappedOps) == false)
return false;
Copy link
Contributor

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?

Copy link
Contributor Author

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

@vfdff vfdff force-pushed the PR54735 branch 2 times, most recently from 5aa207b to 8a732dc Compare June 1, 2024 09:42
@dtcxzyw dtcxzyw requested a review from goldsteinn June 1, 2024 14:17
if (match(R1, m_NonNegative()) && (L0 == X && L1 == Y) &&
isImpliedCondMatchingOperands(LPred, RPred) == true)
return true;
}
Copy link
Contributor

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)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apply your comment, thanks

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))))) {
Copy link
Contributor

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

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.

Copy link
Contributor Author

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 ?

Copy link
Contributor

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.

Copy link
Contributor Author

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
Copy link
Contributor

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.

Copy link
Contributor Author

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

vfdff added 3 commits June 6, 2024 09:24
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;
}
Copy link
Contributor

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...

Copy link
Contributor Author

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 ?

Copy link
Contributor

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.

@goldsteinn
Copy link
Contributor

LGTM. Please wait for an additional approval

@vfdff
Copy link
Contributor Author

vfdff commented Jun 7, 2024

LGTM. Please wait for an additional approval
Thank very much for your reviewing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[optimization] gcc generate better code than clang base on value range propagation
5 participants