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...@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...@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; } } _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits