Skip to content

[ConstraintElim] Simplify cmp after uadd.sat/usub.sat #135603

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

Merged
merged 4 commits into from
Apr 14, 2025

Conversation

el-ev
Copy link
Member

@el-ev el-ev commented Apr 14, 2025

@llvmbot
Copy link
Member

llvmbot commented Apr 14, 2025

@llvm/pr-subscribers-llvm-transforms

Author: Iris (el-ev)

Changes
  • Closes #135557

Full diff: https://github.com/llvm/llvm-project/pull/135603.diff

2 Files Affected:

  • (modified) llvm/lib/Transforms/Scalar/ConstraintElimination.cpp (+16-1)
  • (added) llvm/test/Transforms/ConstraintElimination/uadd-usub-sat.ll (+36)
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 456f5086309cf..ea03b6e5d5570 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1141,6 +1141,8 @@ void State::addInfoFor(BasicBlock &BB) {
         break;
       [[fallthrough]];
     case Intrinsic::abs:
+    case Intrinsic::uadd_sat:
+    case Intrinsic::usub_sat:
       WorkList.push_back(FactOrCheck::getInstFact(DT.getNode(&BB), &I));
       break;
     }
@@ -1891,13 +1893,26 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
         AddFact(CmpInst::ICMP_SGE, CB.Inst, X);
         continue;
       }
-
       if (auto *MinMax = dyn_cast<MinMaxIntrinsic>(CB.Inst)) {
         Pred = ICmpInst::getNonStrictPredicate(MinMax->getPredicate());
         AddFact(Pred, MinMax, MinMax->getLHS());
         AddFact(Pred, MinMax, MinMax->getRHS());
         continue;
       }
+      if (auto *SatI = dyn_cast<SaturatingInst>(CB.Inst)) {
+        switch (SatI->getIntrinsicID()) {
+        default:
+          continue;
+        case Intrinsic::uadd_sat:
+          Pred = ICmpInst::ICMP_UGE;
+          break;
+        case Intrinsic::usub_sat:
+          Pred = ICmpInst::ICMP_ULE;
+          break;
+        }
+        AddFact(Pred, SatI, SatI->getLHS());
+        continue;
+      }
     }
 
     Value *A = nullptr, *B = nullptr;
diff --git a/llvm/test/Transforms/ConstraintElimination/uadd-usub-sat.ll b/llvm/test/Transforms/ConstraintElimination/uadd-usub-sat.ll
new file mode 100644
index 0000000000000..ec30795a3e95a
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/uadd-usub-sat.ll
@@ -0,0 +1,36 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
+
+declare i64 @llvm.uadd.sat.i64(i64, i64)
+declare i64 @llvm.usub.sat.i64(i64, i64)
+
+define i1 @uadd_sat_uge(i64 %a, i64 %b) {
+; CHECK-LABEL: define i1 @uadd_sat_uge(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT:    [[PRECOND:%.*]] = icmp ugt i64 [[A]], [[B]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRECOND]])
+; CHECK-NEXT:    [[ADD_SAT:%.*]] = call i64 @llvm.uadd.sat.i64(i64 [[A]], i64 1)
+; CHECK-NEXT:    ret i1 true
+;
+  %precond = icmp ugt i64 %a, %b
+  call void @llvm.assume(i1 %precond)
+  %add.sat = call i64 @llvm.uadd.sat.i64(i64 %a, i64 1)
+  %cmp = icmp ugt i64 %add.sat, %b
+  ret i1 %cmp
+}
+
+
+define i1 @usub_sat_ule(i64 %a, i64 %b) {
+; CHECK-LABEL: define i1 @usub_sat_ule(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) {
+; CHECK-NEXT:    [[PRECOND:%.*]] = icmp ult i64 [[A]], [[B]]
+; CHECK-NEXT:    call void @llvm.assume(i1 [[PRECOND]])
+; CHECK-NEXT:    [[SUB_SAT:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A]], i64 1)
+; CHECK-NEXT:    ret i1 true
+;
+  %precond = icmp ult i64 %a, %b
+  call void @llvm.assume(i1 %precond)
+  %sub.sat = call i64 @llvm.usub.sat.i64(i64 %a, i64 1)
+  %cmp = icmp ult i64 %sub.sat, %b
+  ret i1 %cmp
+}

@dtcxzyw dtcxzyw requested review from nikic, fhahn and dtcxzyw April 14, 2025 09:26
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.

LGTM. Thank you!

@el-ev el-ev merged commit fe54d1a into main Apr 14, 2025
10 of 11 checks passed
@el-ev el-ev deleted the users/el-ev/sat_constraint branch April 14, 2025 12:15
Copy link
Contributor

@fhahn fhahn left a comment

Choose a reason for hiding this comment

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

Thanks for the improvement!

There still are a number of improvements to simplifying intrinsics, e.g. add_with_overflow is still missing, while we already support ssub_with_overflow.

@nikic
Copy link
Contributor

nikic commented Apr 14, 2025

We could also simplify usub.sat to sub if LHS >= RHS. This patch just adds fact, but we could also simplify.

@el-ev
Copy link
Member Author

el-ev commented Apr 14, 2025

@fhahn @nikic I would like to handle them in some followup patches.

var-const pushed a commit to ldionne/llvm-project that referenced this pull request Apr 17, 2025
@aeubanks
Copy link
Contributor

I believe this is causing a miscompile:

$ cat /tmp/a.ll
define i1 @f(i64 %conv6, i64 %str.coerce, ptr %conv) {
  %a = load i32, ptr %conv, align 4
  %cmp = icmp sgt i32 %a, -1
  %conv2 = zext nneg i32 %a to i64
  %add = add i64 %str.coerce, %conv6
  %spec.select = call i64 @llvm.usub.sat.i64(i64 %conv2, i64 %add)
  ret i1 %cmp
}

declare i64 @llvm.usub.sat.i64(i64, i64)

$ opt -p constraint-elimination -S /tmp/a.ll
define i1 @f(i64 %conv6, i64 %str.coerce, ptr %conv) {
  %a = load i32, ptr %conv, align 4
  %conv2 = zext nneg i32 %a to i64
  %add = add i64 %str.coerce, %conv6
  %spec.select = call i64 @llvm.usub.sat.i64(i64 %conv2, i64 %add)
  ret i1 true
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i64 @llvm.usub.sat.i64(i64, i64) #0

@el-ev
Copy link
Member Author

el-ev commented Apr 18, 2025

I believe this is causing a miscompile:

$ cat /tmp/a.ll
define i1 @f(i64 %conv6, i64 %str.coerce, ptr %conv) {
  %a = load i32, ptr %conv, align 4
  %cmp = icmp sgt i32 %a, -1
  %conv2 = zext nneg i32 %a to i64
  %add = add i64 %str.coerce, %conv6
  %spec.select = call i64 @llvm.usub.sat.i64(i64 %conv2, i64 %add)
  ret i1 %cmp
}

declare i64 @llvm.usub.sat.i64(i64, i64)

$ opt -p constraint-elimination -S /tmp/a.ll
define i1 @f(i64 %conv6, i64 %str.coerce, ptr %conv) {
  %a = load i32, ptr %conv, align 4
  %conv2 = zext nneg i32 %a to i64
  %add = add i64 %str.coerce, %conv6
  %spec.select = call i64 @llvm.usub.sat.i64(i64 %conv2, i64 %add)
  ret i1 true
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare i64 @llvm.usub.sat.i64(i64, i64) #0

The nneg flag on zext is providing some assumption that %a >=0 holds true

@aeubanks
Copy link
Contributor

I believe it's not UB if %a >= 0 is not true, the later instructions just end up being poison

@el-ev
Copy link
Member Author

el-ev commented Apr 18, 2025

@nikic
Copy link
Contributor

nikic commented Apr 18, 2025

@el-ev The problem is the missing check for

if (!isGuaranteedNotToBePoison(&I))
break;
for usub_sat.

@el-ev
Copy link
Member Author

el-ev commented Apr 18, 2025

@nikic Thanks. Could you please take a look at #135744?

@nikic
Copy link
Contributor

nikic commented Apr 18, 2025

@el-ev Would it be possible to fix this separately from adding support for simplifying usub.sat? These are not really related...

aeubanks added a commit that referenced this pull request Apr 18, 2025
@aeubanks
Copy link
Contributor

I've reverted this to keep head green, please reland with the fix

IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
GeorgeARM pushed a commit to GeorgeARM/llvm-project that referenced this pull request May 7, 2025
Ankur-0429 pushed a commit to Ankur-0429/llvm-project that referenced this pull request May 9, 2025
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.

[ConstraintElim] Failure to eliminate cmp of usub.sat
6 participants