https://github.com/el-ev updated https://github.com/llvm/llvm-project/pull/135785
>From b5cac9cccc305a6af33bc0bc30d01965c5e7e333 Mon Sep 17 00:00:00 2001 From: Iris Shi <0...@owo.li> Date: Tue, 15 Apr 2025 20:20:45 +0800 Subject: [PATCH] [ConstraintElim] Simplify `usub_with_overflow` when A uge B --- .../Scalar/ConstraintElimination.cpp | 11 ++++ .../usub-with-overflow.ll | 54 +++++++++++-------- 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp index 15aba43721e57..71afd7a2203ef 100644 --- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp +++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp @@ -1124,6 +1124,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( @@ -1765,6 +1766,16 @@ tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info, Changed = true; 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)) { + replaceAddOrSubOverflowUses(II, A, B, ToRemove); + Changed = true; + } + 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..722116cc6ebd0 100644 --- a/llvm/test/Transforms/ConstraintElimination/usub-with-overflow.ll +++ b/llvm/test/Transforms/ConstraintElimination/usub-with-overflow.ll @@ -9,12 +9,14 @@ 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: [[RES:%.*]] = sub i8 [[B]], [[A]] +; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i8, i1 } poison, i8 [[RES]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = insertvalue { i8, i1 } [[TMP1]], i1 false, 1 +; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[TMP2]], 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-NEXT: [[RES1:%.*]] = extractvalue { i8, i1 } [[TMP2]], 0 +; CHECK-NEXT: ret i8 [[RES1]] ; CHECK: exit.fail: ; CHECK-NEXT: ret i8 0 ; @@ -41,12 +43,14 @@ 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: [[RES:%.*]] = sub i8 [[B]], [[A]] +; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i8, i1 } poison, i8 [[RES]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = insertvalue { i8, i1 } [[TMP1]], i1 false, 1 +; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[TMP2]], 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-NEXT: [[RES1:%.*]] = extractvalue { i8, i1 } [[TMP2]], 0 +; CHECK-NEXT: ret i8 [[RES1]] ; CHECK: exit.fail: ; CHECK-NEXT: ret i8 0 ; @@ -75,13 +79,15 @@ 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: [[OP:%.*]] = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[B]], i8 [[A]]) +; CHECK-NEXT: [[RES:%.*]] = sub i8 [[B]], [[A]] +; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i8, i1 } poison, i8 [[RES]], 0 +; CHECK-NEXT: [[OP:%.*]] = insertvalue { i8, i1 } [[TMP1]], i1 false, 1 ; 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: [[RES:%.*]] = extractvalue { i8, i1 } [[OP]], 0 -; CHECK-NEXT: ret i8 [[RES]] +; CHECK-NEXT: [[RES1:%.*]] = extractvalue { i8, i1 } [[OP]], 0 +; CHECK-NEXT: ret i8 [[RES1]] ; CHECK: exit.fail: ; CHECK-NEXT: ret i8 0 ; @@ -111,12 +117,14 @@ 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: [[RES:%.*]] = sub i8 [[B]], [[A]] +; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i8, i1 } poison, i8 [[RES]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = insertvalue { i8, i1 } [[TMP1]], i1 false, 1 +; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[TMP2]], 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-NEXT: [[RES1:%.*]] = extractvalue { i8, i1 } [[TMP2]], 0 +; CHECK-NEXT: ret i8 [[RES1]] ; CHECK: exit.fail: ; CHECK-NEXT: ret i8 0 ; @@ -147,8 +155,10 @@ 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: [[TMP0:%.*]] = sub i8 [[B]], [[A]] +; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i8, i1 } poison, i8 [[TMP0]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = insertvalue { i8, i1 } [[TMP1]], i1 false, 1 +; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[TMP2]], 1 ; CHECK-NEXT: br i1 [[STATUS]], label [[EXIT_FAIL]], label [[EXIT_OK:%.*]] ; CHECK: exit.ok: ; CHECK-NEXT: ret i8 20 @@ -181,12 +191,14 @@ 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: [[RES:%.*]] = sub i8 [[B]], [[A]] +; CHECK-NEXT: [[TMP1:%.*]] = insertvalue { i8, i1 } poison, i8 [[RES]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = insertvalue { i8, i1 } [[TMP1]], i1 false, 1 +; CHECK-NEXT: [[STATUS:%.*]] = extractvalue { i8, i1 } [[TMP2]], 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-NEXT: [[RES1:%.*]] = extractvalue { i8, i1 } [[TMP2]], 0 +; CHECK-NEXT: ret i8 [[RES1]] ; CHECK: exit.fail: ; CHECK-NEXT: ret i8 0 ; _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits