[llvm] 8e6d481 - [ConstraintElimination] Simplify ssub(A, B) if B s>=b && B s>=0.
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Fri May 13 05:20:25 PDT 2022
Author: Florian Hahn
Date: 2022-05-13T13:19:41+01:00
New Revision: 8e6d481f3b7da224f8dd28a06fa91602e824db18
URL: https://github.com/llvm/llvm-project/commit/8e6d481f3b7da224f8dd28a06fa91602e824db18
DIFF: https://github.com/llvm/llvm-project/commit/8e6d481f3b7da224f8dd28a06fa91602e824db18.diff
LOG: [ConstraintElimination] Simplify ssub(A,B) if B s>=b && B s>=0.
A first patch to use the reasoning in ConstraintElimination to simplify
sub with overflow to a regular sub, if the operation is guaranteed to
not overflow.
Reviewed By: spatel
Differential Revision: https://reviews.llvm.org/D125264
Added:
Modified:
llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
llvm/test/Transforms/ConstraintElimination/ssub-with-overflow.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index ba6e4ee1124f4..8b4a49c56b68e 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -21,6 +21,7 @@
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
+#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/PatternMatch.h"
#include "llvm/InitializePasses.h"
@@ -517,6 +518,55 @@ void State::addInfoFor(BasicBlock &BB) {
WorkList.emplace_back(DT.getNode(Br->getSuccessor(1)), CmpI, true);
}
+static void
+tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info,
+ SmallVectorImpl<Instruction *> &ToRemove) {
+ auto DoesConditionHold = [](CmpInst::Predicate Pred, Value *A, Value *B,
+ ConstraintInfo &Info) {
+ DenseMap<Value *, unsigned> NewIndices;
+ auto R = getConstraint(
+ Pred, A, B, Info.getValue2Index(CmpInst::isSigned(Pred)), NewIndices);
+ if (R.size() < 2 || R.needsNewIndices(NewIndices) || !R.isValid(Info))
+ return false;
+
+ auto &CSToUse = Info.getCS(CmpInst::isSigned(Pred));
+ return CSToUse.isConditionImplied(R.Coefficients);
+ };
+
+ if (II->getIntrinsicID() == 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))
+ return;
+
+ IRBuilder<> Builder(II->getParent(), II->getIterator());
+ Value *Sub = 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);
+ } else if (match(U, m_ExtractValue<1>(m_Value())))
+ U->replaceAllUsesWith(Builder.getFalse());
+ else
+ continue;
+
+ if (U->use_empty()) {
+ auto *I = cast<Instruction>(U);
+ ToRemove.push_back(I);
+ I->setOperand(0, PoisonValue::get(II->getType()));
+ }
+ }
+
+ if (II->use_empty())
+ II->eraseFromParent();
+ }
+}
+
static bool eliminateConstraints(Function &F, DominatorTree &DT) {
bool Changed = false;
DT.updateDFSNumbers();
@@ -540,6 +590,8 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT) {
return std::tie(A.NumIn, A.IsBlock) < std::tie(B.NumIn, B.IsBlock);
});
+ SmallVector<Instruction *> ToRemove;
+
// Finally, process ordered worklist and eliminate implied conditions.
SmallVector<StackEntry, 16> DFSInStack;
for (ConstraintOrBlock &CB : S.WorkList) {
@@ -576,7 +628,11 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT) {
// For a block, check if any CmpInsts become known based on the current set
// of constraints.
if (CB.IsBlock) {
- for (Instruction &I : *CB.BB) {
+ for (Instruction &I : make_early_inc_range(*CB.BB)) {
+ if (auto *II = dyn_cast<WithOverflowInst>(&I)) {
+ tryToSimplifyOverflowMath(II, Info, ToRemove);
+ continue;
+ }
auto *Cmp = dyn_cast<ICmpInst>(&I);
if (!Cmp)
continue;
@@ -699,6 +755,8 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT) {
"updates to CS and DFSInStack are out of sync");
#endif
+ for (Instruction *I : ToRemove)
+ I->eraseFromParent();
return Changed;
}
diff --git a/llvm/test/Transforms/ConstraintElimination/ssub-with-overflow.ll b/llvm/test/Transforms/ConstraintElimination/ssub-with-overflow.ll
index aa1a63aefde00..254a6a662025e 100644
--- a/llvm/test/Transforms/ConstraintElimination/ssub-with-overflow.ll
+++ b/llvm/test/Transforms/ConstraintElimination/ssub-with-overflow.ll
@@ -11,12 +11,10 @@ define i8 @ssub_no_overflow_due_to_or_conds(i8 %a, i8 %b) {
; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[C_2]], [[C_1]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[EXIT_FAIL:%.*]], label [[MATH:%.*]]
; CHECK: math:
-; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.ssub.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: [[TMP0:%.*]] = 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-NEXT: ret i8 [[TMP0]]
; CHECK: exit.fail:
; CHECK-NEXT: ret i8 0
;
@@ -49,13 +47,12 @@ define i8 @ssub_no_overflow_due_to_or_conds_result_used(i8 %a, i8 %b) {
; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[C_2]], [[C_1]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[EXIT_FAIL:%.*]], label [[MATH:%.*]]
; CHECK: math:
+; CHECK-NEXT: [[TMP0:%.*]] = sub i8 [[B]], [[A]]
; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.ssub.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-NEXT: ret i8 [[TMP0]]
; CHECK: exit.fail:
; CHECK-NEXT: ret i8 0
;
@@ -87,12 +84,10 @@ define i8 @ssub_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.ssub.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: [[TMP0:%.*]] = 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-NEXT: ret i8 [[TMP0]]
; CHECK: exit.fail:
; CHECK-NEXT: ret i8 0
;
@@ -123,9 +118,7 @@ define i8 @ssub_no_overflow_due_to_and_conds_sub_result_not_used(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.ssub.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:
More information about the llvm-commits
mailing list