[llvm-branch-commits] [llvm] [ConstraintElim] Simplify `usub_with_overflow` when A uge B (PR #135785)

Iris Shi via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Apr 30 03:20:30 PDT 2025


https://github.com/el-ev updated https://github.com/llvm/llvm-project/pull/135785

>From c5328e2075b5f98311eb9c9657da79d800cf28f4 Mon Sep 17 00:00:00 2001
From: Iris Shi <0.0 at owo.li>
Date: Tue, 15 Apr 2025 20:20:45 +0800
Subject: [PATCH 1/2] [ConstraintElim] Simplify `usub_with_overflow` when A uge
 B

---
 .../Scalar/ConstraintElimination.cpp          | 10 ++++++
 .../usub-with-overflow.ll                     | 33 +++++++------------
 2 files changed, 21 insertions(+), 22 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 6d17b36b7d9ea..e030f0fac4c0d 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1123,6 +1123,7 @@ void State::addInfoFor(BasicBlock &BB) {
     // Enqueue overflow intrinsics for simplification.
     case Intrinsic::sadd_with_overflow:
     case Intrinsic::ssub_with_overflow:
+    case Intrinsic::usub_with_overflow:
     case Intrinsic::ucmp:
     case Intrinsic::scmp:
       WorkList.push_back(
@@ -1785,6 +1786,15 @@ tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info,
     Changed = replaceSubOverflowUses(II, A, B, ToRemove);
     break;
   }
+  case Intrinsic::usub_with_overflow: {
+    // usub overflows iff A < B
+    // TODO: If the operation is guaranteed to overflow, we could
+    // also apply some simplifications.
+    if (DoesConditionHold(CmpInst::ICMP_UGE, A, B, Info)) {
+      Changed = replaceSubOverflowUses(II, A, B, ToRemove);
+    }
+    break;
+  }
   }
 
   return Changed;
diff --git a/llvm/test/Transforms/ConstraintElimination/usub-with-overflow.ll b/llvm/test/Transforms/ConstraintElimination/usub-with-overflow.ll
index 06bfd8269d97d..0a3c4eb00fd25 100644
--- a/llvm/test/Transforms/ConstraintElimination/usub-with-overflow.ll
+++ b/llvm/test/Transforms/ConstraintElimination/usub-with-overflow.ll
@@ -9,11 +9,9 @@ define i8 @usub_no_overflow_due_to_cmp_condition(i8 %a, i8 %b) {
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp uge i8 [[B:%.*]], [[A:%.*]]
 ; CHECK-NEXT:    br i1 [[C_1]], label [[MATH:%.*]], label [[EXIT_FAIL:%.*]]
 ; CHECK:       math:
-; CHECK-NEXT:    [[OP:%.*]] = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[B]], i8 [[A]])
-; CHECK-NEXT:    [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1
-; CHECK-NEXT:    br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
+; CHECK-NEXT:    [[RES:%.*]] = sub i8 [[B]], [[A]]
+; CHECK-NEXT:    br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
 ; CHECK:       exit.ok:
-; CHECK-NEXT:    [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0
 ; CHECK-NEXT:    ret i8 [[RES]]
 ; CHECK:       exit.fail:
 ; CHECK-NEXT:    ret i8 0
@@ -41,11 +39,9 @@ define i8 @usub_no_overflow_due_to_cmp_condition2(i8 %a, i8 %b) {
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ule i8 [[B:%.*]], [[A:%.*]]
 ; CHECK-NEXT:    br i1 [[C_1]], label [[EXIT_FAIL:%.*]], label [[MATH:%.*]]
 ; CHECK:       math:
-; CHECK-NEXT:    [[OP:%.*]] = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[B]], i8 [[A]])
-; CHECK-NEXT:    [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1
-; CHECK-NEXT:    br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
+; CHECK-NEXT:    [[RES:%.*]] = sub i8 [[B]], [[A]]
+; CHECK-NEXT:    br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
 ; CHECK:       exit.ok:
-; CHECK-NEXT:    [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0
 ; CHECK-NEXT:    ret i8 [[RES]]
 ; CHECK:       exit.fail:
 ; CHECK-NEXT:    ret i8 0
@@ -75,12 +71,11 @@ define i8 @sub_no_overflow_due_to_cmp_condition_result_used(i8 %a, i8 %b) {
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ule i8 [[B:%.*]], [[A:%.*]]
 ; CHECK-NEXT:    br i1 [[C_1]], label [[EXIT_FAIL:%.*]], label [[MATH:%.*]]
 ; CHECK:       math:
+; CHECK-NEXT:    [[RES:%.*]] = sub i8 [[B]], [[A]]
 ; CHECK-NEXT:    [[OP:%.*]] = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[B]], i8 [[A]])
 ; CHECK-NEXT:    call void @use_res({ i8, i1 } [[OP]])
-; CHECK-NEXT:    [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1
-; CHECK-NEXT:    br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
+; CHECK-NEXT:    br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
 ; CHECK:       exit.ok:
-; CHECK-NEXT:    [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0
 ; CHECK-NEXT:    ret i8 [[RES]]
 ; CHECK:       exit.fail:
 ; CHECK-NEXT:    ret i8 0
@@ -111,11 +106,9 @@ define i8 @usub_no_overflow_due_to_or_conds(i8 %a, i8 %b) {
 ; CHECK-NEXT:    [[OR:%.*]] = or i1 [[C_2]], [[C_1]]
 ; CHECK-NEXT:    br i1 [[OR]], label [[EXIT_FAIL:%.*]], label [[MATH:%.*]]
 ; CHECK:       math:
-; CHECK-NEXT:    [[OP:%.*]] = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[B]], i8 [[A]])
-; CHECK-NEXT:    [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1
-; CHECK-NEXT:    br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
+; CHECK-NEXT:    [[RES:%.*]] = sub i8 [[B]], [[A]]
+; CHECK-NEXT:    br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
 ; CHECK:       exit.ok:
-; CHECK-NEXT:    [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0
 ; CHECK-NEXT:    ret i8 [[RES]]
 ; CHECK:       exit.fail:
 ; CHECK-NEXT:    ret i8 0
@@ -147,9 +140,7 @@ define i8 @usub_no_overflow_due_to_or_conds_sub_result_not_used(i8 %a, i8 %b) {
 ; CHECK-NEXT:    [[OR:%.*]] = or i1 [[C_2]], [[C_1]]
 ; CHECK-NEXT:    br i1 [[OR]], label [[EXIT_FAIL:%.*]], label [[MATH:%.*]]
 ; CHECK:       math:
-; CHECK-NEXT:    [[OP:%.*]] = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[B]], i8 [[A]])
-; CHECK-NEXT:    [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1
-; CHECK-NEXT:    br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
+; CHECK-NEXT:    br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
 ; CHECK:       exit.ok:
 ; CHECK-NEXT:    ret i8 20
 ; CHECK:       exit.fail:
@@ -181,11 +172,9 @@ define i8 @usub_no_overflow_due_to_and_conds(i8 %a, i8 %b) {
 ; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_2]], [[C_1]]
 ; CHECK-NEXT:    br i1 [[AND]], label [[MATH:%.*]], label [[EXIT_FAIL:%.*]]
 ; CHECK:       math:
-; CHECK-NEXT:    [[OP:%.*]] = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[B]], i8 [[A]])
-; CHECK-NEXT:    [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1
-; CHECK-NEXT:    br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
+; CHECK-NEXT:    [[RES:%.*]] = sub i8 [[B]], [[A]]
+; CHECK-NEXT:    br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
 ; CHECK:       exit.ok:
-; CHECK-NEXT:    [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0
 ; CHECK-NEXT:    ret i8 [[RES]]
 ; CHECK:       exit.fail:
 ; CHECK-NEXT:    ret i8 0

>From 398a45d417a8e9f2880c6b967fe8b44806030abe Mon Sep 17 00:00:00 2001
From: Iris Shi <0.0 at owo.li>
Date: Wed, 30 Apr 2025 18:16:40 +0800
Subject: [PATCH 2/2] apply suggestions

---
 .../Scalar/ConstraintElimination.cpp          | 61 +++++--------------
 1 file changed, 15 insertions(+), 46 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index ac8aff442b6c4..cc1a29cebbd56 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1674,48 +1674,19 @@ void ConstraintInfo::addFactImpl(CmpInst::Predicate Pred, Value *A, Value *B,
   }
 }
 
-static bool replaceAddOverflowUses(IntrinsicInst *II, Value *A, Value *B,
-                                   SmallVectorImpl<Instruction *> &ToRemove) {
-  bool Changed = false;
-  IRBuilder<> Builder(II->getParent(), II->getIterator());
-  Value *Add = nullptr;
-  for (User *U : make_early_inc_range(II->users())) {
-    if (match(U, m_ExtractValue<0>(m_Value()))) {
-      if (!Add)
-        Add = Builder.CreateAdd(A, B);
-      U->replaceAllUsesWith(Add);
-      Changed = true;
-    } else if (match(U, m_ExtractValue<1>(m_Value()))) {
-      U->replaceAllUsesWith(Builder.getFalse());
-      Changed = true;
-    } else
-      continue;
-
-    if (U->use_empty()) {
-      auto *I = cast<Instruction>(U);
-      ToRemove.push_back(I);
-      I->setOperand(0, PoisonValue::get(II->getType()));
-      Changed = true;
-    }
-  }
-
-  if (II->use_empty()) {
-    II->eraseFromParent();
-    Changed = true;
-  }
-  return Changed;
-}
-
-static bool replaceSubOverflowUses(IntrinsicInst *II, Value *A, Value *B,
-                                   SmallVectorImpl<Instruction *> &ToRemove) {
+static bool
+replaceAddOrSubOverflowUses(IntrinsicInst *II, Value *A, Value *B,
+                            SmallVectorImpl<Instruction *> &ToRemove) {
+  bool IsAdd = II->getIntrinsicID() == Intrinsic::sadd_with_overflow ||
+               II->getIntrinsicID() == Intrinsic::uadd_with_overflow;
   bool Changed = false;
   IRBuilder<> Builder(II->getParent(), II->getIterator());
-  Value *Sub = nullptr;
+  Value *AddOrSub = nullptr;
   for (User *U : make_early_inc_range(II->users())) {
     if (match(U, m_ExtractValue<0>(m_Value()))) {
-      if (!Sub)
-        Sub = Builder.CreateSub(A, B);
-      U->replaceAllUsesWith(Sub);
+      if (!AddOrSub)
+        AddOrSub = IsAdd ? Builder.CreateAdd(A, B) : Builder.CreateSub(A, B);
+      U->replaceAllUsesWith(AddOrSub);
       Changed = true;
     } else if (match(U, m_ExtractValue<1>(m_Value()))) {
       U->replaceAllUsesWith(Builder.getFalse());
@@ -1761,15 +1732,13 @@ tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info,
   default:
     llvm_unreachable("Unexpected intrinsic.");
   case Intrinsic::sadd_with_overflow: {
-    bool ASgeZero = DoesConditionHold(CmpInst::ICMP_SGE, A, Zero, Info);
-    bool BSgeZero = DoesConditionHold(CmpInst::ICMP_SGE, B, Zero, Info);
-    bool ASleZero = DoesConditionHold(CmpInst::ICMP_SLE, A, Zero, Info);
-    bool BSleZero = DoesConditionHold(CmpInst::ICMP_SLE, B, Zero, Info);
-
     // If A and B have different signs, sadd.with.overflow(a, b) should not
     // overflow.
-    if ((ASgeZero && BSleZero) || (ASleZero && BSgeZero)) {
-      Changed = replaceAddOverflowUses(II, A, B, ToRemove);
+    if ((DoesConditionHold(CmpInst::ICMP_SGE, A, Zero, Info) &&
+         DoesConditionHold(CmpInst::ICMP_SLE, B, Zero, Info)) ||
+        (DoesConditionHold(CmpInst::ICMP_SLE, A, Zero, Info) &&
+         DoesConditionHold(CmpInst::ICMP_SGE, B, Zero, Info))) {
+      Changed = replaceAddOrSubOverflowUses(II, A, B, ToRemove);
       break;
     }
     break;
@@ -1780,7 +1749,7 @@ tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info,
     if (!DoesConditionHold(CmpInst::ICMP_SGE, A, B, Info) ||
         !DoesConditionHold(CmpInst::ICMP_SGE, B, Zero, Info))
       return false;
-    Changed = replaceSubOverflowUses(II, A, B, ToRemove);
+    Changed = replaceAddOrSubOverflowUses(II, A, B, ToRemove);
     break;
   }
   }



More information about the llvm-branch-commits mailing list