[llvm] [ConstraintElim] Simplify `sadd_with_overflow` if A and B have different signs (PR #135784)

via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 15 05:24:52 PDT 2025


https://github.com/el-ev created https://github.com/llvm/llvm-project/pull/135784

[ConstraintElim] Simplify `sadd_with_overflow` if A and B have different signs

update test

refactor

>From 40e8a0df33e8404a56a638c378519f57e8f2032d Mon Sep 17 00:00:00 2001
From: Iris Shi <0.0 at owo.li>
Date: Tue, 15 Apr 2025 19:55:18 +0800
Subject: [PATCH 1/3] [ConstraintElim] Simplify `sadd_with_overflow` if A and B
 have different signs

---
 .../Scalar/ConstraintElimination.cpp          |  63 +++-
 .../sadd-with-overflow.ll                     | 306 ++++++++++++++++++
 2 files changed, 367 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/Transforms/ConstraintElimination/sadd-with-overflow.ll

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 31e057baee2bf..73977bd7aa61f 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1120,7 +1120,8 @@ void State::addInfoFor(BasicBlock &BB) {
       }
       break;
     }
-    // Enqueue ssub_with_overflow for simplification.
+    // Enqueue overflow intrinsics for simplification.
+    case Intrinsic::sadd_with_overflow:
     case Intrinsic::ssub_with_overflow:
     case Intrinsic::ucmp:
     case Intrinsic::scmp:
@@ -1675,6 +1676,38 @@ 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) {
   bool Changed = false;
@@ -1721,7 +1754,30 @@ tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info,
   };
 
   bool Changed = false;
-  if (II->getIntrinsicID() == Intrinsic::ssub_with_overflow) {
+  switch (II->getIntrinsicID()) {
+  default:
+    llvm_unreachable("Unexpected intrinsic.");
+  case Intrinsic::sadd_with_overflow: {
+    Value *A = II->getArgOperand(0);
+    Value *B = II->getArgOperand(1);
+    bool ASgeZero = DoesConditionHold(CmpInst::ICMP_SGE, A,
+                                      ConstantInt::get(A->getType(), 0), Info);
+    bool BSgeZero = DoesConditionHold(CmpInst::ICMP_SGE, B,
+                                      ConstantInt::get(B->getType(), 0), Info);
+    bool ASleZero = DoesConditionHold(CmpInst::ICMP_SLE, A,
+                                      ConstantInt::get(A->getType(), 0), Info);
+    bool BSleZero = DoesConditionHold(CmpInst::ICMP_SLE, B,
+                                      ConstantInt::get(B->getType(), 0), 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);
+      break;
+    }
+    break;
+  }
+  case Intrinsic::ssub_with_overflow: {
     // If A s>= B && B s>= 0, ssub.with.overflow(a, b) should not overflow and
     // can be simplified to a regular sub.
     Value *A = II->getArgOperand(0);
@@ -1731,7 +1787,10 @@ tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info,
                            ConstantInt::get(A->getType(), 0), Info))
       return false;
     Changed = replaceSubOverflowUses(II, A, B, ToRemove);
+    break;
   }
+  }
+
   return Changed;
 }
 
diff --git a/llvm/test/Transforms/ConstraintElimination/sadd-with-overflow.ll b/llvm/test/Transforms/ConstraintElimination/sadd-with-overflow.ll
new file mode 100644
index 0000000000000..50712fa6330b3
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/sadd-with-overflow.ll
@@ -0,0 +1,306 @@
+; 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 { i8, i1 } @llvm.sadd.with.overflow.i8(i8, i8)
+
+define i8 @sadd_no_overflow_due_to_cmp_condition(i8 %a, i8 %b) {
+; CHECK-LABEL: define i8 @sadd_no_overflow_due_to_cmp_condition(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp sge i8 [[A]], 0
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sle i8 [[B]], 0
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_1]], [[C_2]]
+; CHECK-NEXT:    br i1 [[AND]], label %[[MATH:.*]], label %[[EXIT_FAIL:.*]]
+; CHECK:       [[MATH]]:
+; CHECK-NEXT:    [[OP:%.*]] = tail call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 [[B]])
+; CHECK-NEXT:    [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1
+; CHECK-NEXT:    br i1 [[STATUS]], label %[[EXIT_FAIL]], label %[[EXIT_OK:.*]]
+; CHECK:       [[EXIT_OK]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = extractvalue { i8, i1 } [[OP]], 0
+; CHECK-NEXT:    ret i8 [[TMP0]]
+; CHECK:       [[EXIT_FAIL]]:
+; CHECK-NEXT:    ret i8 0
+;
+entry:
+  %c.1 = icmp sge i8 %a, 0
+  %c.2 = icmp sle i8 %b, 0
+  %and = and i1 %c.1, %c.2
+  br i1 %and, label %math, label %exit.fail
+
+math:
+  %op = tail call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %a, i8 %b)
+  %status = extractvalue { i8, i1 } %op, 1
+  br i1 %status, label %exit.fail, label %exit.ok
+
+exit.ok:
+  %res = extractvalue { i8, i1 } %op, 0
+  ret i8 %res
+
+exit.fail:
+  ret i8 0
+}
+
+define i8 @sadd_no_overflow_due_to_cmp_condition2(i8 %a, i8 %b) {
+; CHECK-LABEL: define i8 @sadd_no_overflow_due_to_cmp_condition2(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp slt i8 [[A]], 64
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sle i8 [[B]], 64
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_1]], [[C_2]]
+; CHECK-NEXT:    br i1 [[AND]], label %[[MATH:.*]], label %[[EXIT_FAIL:.*]]
+; CHECK:       [[MATH]]:
+; CHECK-NEXT:    [[OP:%.*]] = tail call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 [[B]])
+; CHECK-NEXT:    [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1
+; CHECK-NEXT:    br i1 [[STATUS]], label %[[EXIT_FAIL]], label %[[EXIT_OK:.*]]
+; CHECK:       [[EXIT_OK]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = extractvalue { i8, i1 } [[OP]], 0
+; CHECK-NEXT:    ret i8 [[TMP0]]
+; CHECK:       [[EXIT_FAIL]]:
+; CHECK-NEXT:    ret i8 0
+;
+entry:
+  %c.1 = icmp slt i8 %a, 64
+  %c.2 = icmp sle i8 %b, 64
+  %and = and i1 %c.1, %c.2
+  br i1 %and, label %math, label %exit.fail
+
+math:
+  %op = tail call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %a, i8 %b)
+  %status = extractvalue { i8, i1 } %op, 1
+  br i1 %status, label %exit.fail, label %exit.ok
+
+exit.ok:
+  %res = extractvalue { i8, i1 } %op, 0
+  ret i8 %res
+
+exit.fail:
+  ret i8 0
+}
+
+declare void @use_res({ i8, i1 })
+
+define i8 @sadd_no_overflow_due_to_cmp_condition_result_used(i8 %a, i8 %b) {
+; CHECK-LABEL: define i8 @sadd_no_overflow_due_to_cmp_condition_result_used(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp sge i8 [[A]], 0
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sle i8 [[B]], 0
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_1]], [[C_2]]
+; CHECK-NEXT:    br i1 [[AND]], label %[[MATH:.*]], label %[[EXIT_FAIL:.*]]
+; CHECK:       [[MATH]]:
+; CHECK-NEXT:    [[OP:%.*]] = tail call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 [[B]])
+; 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:       [[EXIT_OK]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = extractvalue { i8, i1 } [[OP]], 0
+; CHECK-NEXT:    ret i8 [[TMP0]]
+; CHECK:       [[EXIT_FAIL]]:
+; CHECK-NEXT:    ret i8 0
+;
+entry:
+  %c.1 = icmp sge i8 %a, 0
+  %c.2 = icmp sle i8 %b, 0
+  %and = and i1 %c.1, %c.2
+  br i1 %and, label %math, label %exit.fail
+
+math:
+  %op = tail call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %a, i8 %b)
+  call void @use_res({ i8, i1 } %op)
+  %status = extractvalue { i8, i1 } %op, 1
+  br i1 %status, label %exit.fail, label %exit.ok
+
+exit.ok:
+  %res = extractvalue { i8, i1 } %op, 0
+  ret i8 %res
+
+exit.fail:
+  ret i8 0
+}
+
+define i8 @sadd_no_overflow_due_to_or_conds(i8 %a, i8 %b) {
+; CHECK-LABEL: define i8 @sadd_no_overflow_due_to_or_conds(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp eq i8 [[A]], 0
+; CHECK-NEXT:    [[C_2:%.*]] = icmp eq i8 [[B]], 0
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[C_1]], [[C_2]]
+; CHECK-NEXT:    br i1 [[OR]], label %[[MATH:.*]], label %[[EXIT_FAIL:.*]]
+; CHECK:       [[MATH]]:
+; CHECK-NEXT:    [[OP:%.*]] = tail call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 [[B]])
+; CHECK-NEXT:    [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1
+; CHECK-NEXT:    br i1 [[STATUS]], 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
+;
+entry:
+  %c.1 = icmp eq i8 %a, 0
+  %c.2 = icmp eq i8 %b, 0
+  %or = or i1 %c.1, %c.2
+  br i1 %or, label %math, label %exit.fail
+
+math:
+  %op = tail call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %a, i8 %b)
+  %status = extractvalue { i8, i1 } %op, 1
+  br i1 %status, label %exit.fail, label %exit.ok
+
+exit.ok:
+  %res = extractvalue { i8, i1 } %op, 0
+  ret i8 %res
+
+exit.fail:
+  ret i8 0
+}
+
+define i8 @sadd_no_overflow_due_to_and_conds(i8 %a, i8 %b) {
+; CHECK-LABEL: define i8 @sadd_no_overflow_due_to_and_conds(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp sge i8 [[A]], 0
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sle i8 [[A]], 63
+; CHECK-NEXT:    [[C_3:%.*]] = icmp sge i8 [[B]], 0
+; CHECK-NEXT:    [[C_4:%.*]] = icmp sle i8 [[B]], 63
+; CHECK-NEXT:    [[AND1:%.*]] = and i1 [[C_1]], [[C_2]]
+; CHECK-NEXT:    [[AND2:%.*]] = and i1 [[C_3]], [[C_4]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[AND1]], [[AND2]]
+; CHECK-NEXT:    br i1 [[AND]], label %[[MATH:.*]], label %[[EXIT_FAIL:.*]]
+; CHECK:       [[MATH]]:
+; CHECK-NEXT:    [[OP:%.*]] = tail call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 [[B]])
+; CHECK-NEXT:    [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1
+; CHECK-NEXT:    br i1 [[STATUS]], 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
+;
+entry:
+  %c.1 = icmp sge i8 %a, 0
+  %c.2 = icmp sle i8 %a, 63
+  %c.3 = icmp sge i8 %b, 0
+  %c.4 = icmp sle i8 %b, 63
+  %and1 = and i1 %c.1, %c.2
+  %and2 = and i1 %c.3, %c.4
+  %and = and i1 %and1, %and2
+  br i1 %and, label %math, label %exit.fail
+
+math:
+  %op = tail call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %a, i8 %b)
+  %status = extractvalue { i8, i1 } %op, 1
+  br i1 %status, label %exit.fail, label %exit.ok
+
+exit.ok:
+  %res = extractvalue { i8, i1 } %op, 0
+  ret i8 %res
+
+exit.fail:
+  ret i8 0
+}
+
+define i8 @sadd_may_overflow1(i8 %a, i8 %b) {
+; CHECK-LABEL: define i8 @sadd_may_overflow1(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp sge i8 [[A]], 64
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sge i8 [[B]], 64
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[C_1]], [[C_2]]
+; CHECK-NEXT:    br i1 [[OR]], label %[[EXIT_FAIL:.*]], label %[[MATH:.*]]
+; CHECK:       [[MATH]]:
+; CHECK-NEXT:    [[OP:%.*]] = tail call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 [[B]])
+; CHECK-NEXT:    [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1
+; CHECK-NEXT:    br i1 [[STATUS]], label %[[EXIT_FAIL]], label %[[EXIT_OK:.*]]
+; CHECK:       [[EXIT_OK]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = extractvalue { i8, i1 } [[OP]], 0
+; CHECK-NEXT:    ret i8 [[TMP0]]
+; CHECK:       [[EXIT_FAIL]]:
+; CHECK-NEXT:    ret i8 0
+;
+entry:
+  %c.1 = icmp sge i8 %a, 64
+  %c.2 = icmp sge i8 %b, 64
+  %or = or i1 %c.1, %c.2
+  br i1 %or, label %exit.fail, label %math
+
+math:
+  %op = tail call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %a, i8 %b)
+  %status = extractvalue { i8, i1 } %op, 1
+  br i1 %status, label %exit.fail, label %exit.ok
+
+exit.ok:
+  %res = extractvalue { i8, i1 } %op, 0
+  ret i8 %res
+
+exit.fail:
+  ret i8 0
+}
+
+define i8 @sadd_may_overflow2(i8 %a, i8 %b) {
+; CHECK-LABEL: define i8 @sadd_may_overflow2(
+; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp sle i8 [[A]], -65
+; CHECK-NEXT:    [[C_2:%.*]] = icmp sle i8 [[B]], -65
+; CHECK-NEXT:    [[OR:%.*]] = or i1 [[C_1]], [[C_2]]
+; CHECK-NEXT:    br i1 [[OR]], label %[[EXIT_FAIL:.*]], label %[[MATH:.*]]
+; CHECK:       [[MATH]]:
+; CHECK-NEXT:    [[OP:%.*]] = tail call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 [[B]])
+; CHECK-NEXT:    [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1
+; CHECK-NEXT:    br i1 [[STATUS]], label %[[EXIT_FAIL]], label %[[EXIT_OK:.*]]
+; CHECK:       [[EXIT_OK]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = extractvalue { i8, i1 } [[OP]], 0
+; CHECK-NEXT:    ret i8 [[TMP0]]
+; CHECK:       [[EXIT_FAIL]]:
+; CHECK-NEXT:    ret i8 0
+;
+entry:
+  %c.1 = icmp sle i8 %a, -65
+  %c.2 = icmp sle i8 %b, -65
+  %or = or i1 %c.1, %c.2
+  br i1 %or, label %exit.fail, label %math
+
+math:
+  %op = tail call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %a, i8 %b)
+  %status = extractvalue { i8, i1 } %op, 1
+  br i1 %status, label %exit.fail, label %exit.ok
+
+exit.ok:
+  %res = extractvalue { i8, i1 } %op, 0
+  ret i8 %res
+
+exit.fail:
+  ret i8 0
+}
+
+define i8 @sadd_known_overflow(i8 %a) {
+; CHECK-LABEL: define i8 @sadd_known_overflow(
+; CHECK-SAME: i8 [[A:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[C_1:%.*]] = icmp eq i8 [[A]], 127
+; CHECK-NEXT:    br i1 [[C_1]], label %[[MATH:.*]], label %[[EXIT_FAIL:.*]]
+; CHECK:       [[MATH]]:
+; CHECK-NEXT:    [[OP:%.*]] = tail call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 1)
+; CHECK-NEXT:    [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1
+; CHECK-NEXT:    br i1 [[STATUS]], label %[[EXIT_OK:.*]], label %[[EXIT_FAIL]]
+; CHECK:       [[EXIT_OK]]:
+; CHECK-NEXT:    ret i8 1
+; CHECK:       [[EXIT_FAIL]]:
+; CHECK-NEXT:    ret i8 0
+;
+entry:
+  %c.1 = icmp eq i8 %a, 127
+  br i1 %c.1, label %math, label %exit.fail
+
+math:
+  %op = tail call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 %a, i8 1)
+  %status = extractvalue { i8, i1 } %op, 1
+  br i1 %status, label %exit.ok, label %exit.fail
+
+exit.ok:
+  ret i8 1
+
+exit.fail:
+  ret i8 0
+}

>From ae8fb06de63b4c3dc146e376dd3e961d283fa7d4 Mon Sep 17 00:00:00 2001
From: Iris Shi <0.0 at owo.li>
Date: Tue, 15 Apr 2025 19:58:22 +0800
Subject: [PATCH 2/3] update test

---
 .../ConstraintElimination/sadd-with-overflow.ll       | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/llvm/test/Transforms/ConstraintElimination/sadd-with-overflow.ll b/llvm/test/Transforms/ConstraintElimination/sadd-with-overflow.ll
index 50712fa6330b3..5d0a902a90783 100644
--- a/llvm/test/Transforms/ConstraintElimination/sadd-with-overflow.ll
+++ b/llvm/test/Transforms/ConstraintElimination/sadd-with-overflow.ll
@@ -12,11 +12,9 @@ define i8 @sadd_no_overflow_due_to_cmp_condition(i8 %a, i8 %b) {
 ; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_1]], [[C_2]]
 ; CHECK-NEXT:    br i1 [[AND]], label %[[MATH:.*]], label %[[EXIT_FAIL:.*]]
 ; CHECK:       [[MATH]]:
-; CHECK-NEXT:    [[OP:%.*]] = tail call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 [[B]])
-; CHECK-NEXT:    [[STATUS:%.*]] = extractvalue { i8, i1 } [[OP]], 1
-; CHECK-NEXT:    br i1 [[STATUS]], label %[[EXIT_FAIL]], label %[[EXIT_OK:.*]]
+; CHECK-NEXT:    [[TMP0:%.*]] = add i8 [[A]], [[B]]
+; CHECK-NEXT:    br i1 false, label %[[EXIT_FAIL]], label %[[EXIT_OK:.*]]
 ; CHECK:       [[EXIT_OK]]:
-; CHECK-NEXT:    [[TMP0:%.*]] = extractvalue { i8, i1 } [[OP]], 0
 ; CHECK-NEXT:    ret i8 [[TMP0]]
 ; CHECK:       [[EXIT_FAIL]]:
 ; CHECK-NEXT:    ret i8 0
@@ -88,12 +86,11 @@ define i8 @sadd_no_overflow_due_to_cmp_condition_result_used(i8 %a, i8 %b) {
 ; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_1]], [[C_2]]
 ; CHECK-NEXT:    br i1 [[AND]], label %[[MATH:.*]], label %[[EXIT_FAIL:.*]]
 ; CHECK:       [[MATH]]:
+; CHECK-NEXT:    [[TMP0:%.*]] = add i8 [[A]], [[B]]
 ; CHECK-NEXT:    [[OP:%.*]] = tail call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[A]], i8 [[B]])
 ; 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:    [[TMP0:%.*]] = extractvalue { i8, i1 } [[OP]], 0
 ; CHECK-NEXT:    ret i8 [[TMP0]]
 ; CHECK:       [[EXIT_FAIL]]:
 ; CHECK-NEXT:    ret i8 0

>From ac8a2f090b5825aaab5a38bca7c99e71a5587c6f Mon Sep 17 00:00:00 2001
From: Iris Shi <0.0 at owo.li>
Date: Tue, 15 Apr 2025 20:10:52 +0800
Subject: [PATCH 3/3] refactor

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

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 73977bd7aa61f..7ebd91dbb8ce4 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1754,21 +1754,20 @@ tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info,
   };
 
   bool Changed = false;
+  Value *A = II->getArgOperand(0);
+  Value *B = II->getArgOperand(1);
+  Type *Ty = II->getType();
+  auto *Zero = ConstantInt::get(Ty, 0);
+
   switch (II->getIntrinsicID()) {
   default:
     llvm_unreachable("Unexpected intrinsic.");
   case Intrinsic::sadd_with_overflow: {
-    Value *A = II->getArgOperand(0);
-    Value *B = II->getArgOperand(1);
-    bool ASgeZero = DoesConditionHold(CmpInst::ICMP_SGE, A,
-                                      ConstantInt::get(A->getType(), 0), Info);
-    bool BSgeZero = DoesConditionHold(CmpInst::ICMP_SGE, B,
-                                      ConstantInt::get(B->getType(), 0), Info);
-    bool ASleZero = DoesConditionHold(CmpInst::ICMP_SLE, A,
-                                      ConstantInt::get(A->getType(), 0), Info);
-    bool BSleZero = DoesConditionHold(CmpInst::ICMP_SLE, B,
-                                      ConstantInt::get(B->getType(), 0), Info);
-    
+    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)) {
@@ -1780,11 +1779,8 @@ tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info,
   case Intrinsic::ssub_with_overflow: {
     // If A s>= B && B s>= 0, ssub.with.overflow(a, b) should not overflow and
     // can be simplified to a regular sub.
-    Value *A = II->getArgOperand(0);
-    Value *B = II->getArgOperand(1);
     if (!DoesConditionHold(CmpInst::ICMP_SGE, A, B, Info) ||
-        !DoesConditionHold(CmpInst::ICMP_SGE, B,
-                           ConstantInt::get(A->getType(), 0), Info))
+        !DoesConditionHold(CmpInst::ICMP_SGE, B, Zero, Info))
       return false;
     Changed = replaceSubOverflowUses(II, A, B, ToRemove);
     break;



More information about the llvm-commits mailing list