[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 08:26:47 PDT 2025
https://github.com/el-ev updated https://github.com/llvm/llvm-project/pull/135784
>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/4] [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/4] 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/4] 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;
>From c48ded7c9b7f6d83efae2f568c4db6df1d4995a7 Mon Sep 17 00:00:00 2001
From: Iris Shi <0.0 at owo.li>
Date: Tue, 15 Apr 2025 23:19:00 +0800
Subject: [PATCH 4/4] fix wrong type
---
llvm/lib/Transforms/Scalar/ConstraintElimination.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 7ebd91dbb8ce4..6d17b36b7d9ea 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1756,7 +1756,7 @@ tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info,
bool Changed = false;
Value *A = II->getArgOperand(0);
Value *B = II->getArgOperand(1);
- Type *Ty = II->getType();
+ Type *Ty = A->getType();
auto *Zero = ConstantInt::get(Ty, 0);
switch (II->getIntrinsicID()) {
More information about the llvm-commits
mailing list