diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp --- 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,40 @@ WorkList.emplace_back(DT.getNode(Br->getSuccessor(1)), CmpI, true); } +static void tryToSimplifyOverflowMath(IntrinsicInst *II, ConstraintInfo &Info) { + auto DoesConditionHold = [](CmpInst::Predicate Pred, Value *A, Value *B, + ConstraintInfo &Info) { + DenseMap 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 && A 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, A, + ConstantInt::get(A->getType(), 0), Info)) + return; + + IRBuilder<> Builder(II->getParent(), II->getIterator()); + Value *Sub = Builder.CreateSub(A, B); + for (User *U : make_early_inc_range(II->users())) { + if (match(U, m_ExtractValue<0>(m_Value()))) + U->replaceAllUsesWith(Sub); + else if (match(U, m_ExtractValue<1>(m_Value()))) + U->replaceAllUsesWith(Builder.getFalse()); + } + } +} + static bool eliminateConstraints(Function &F, DominatorTree &DT) { bool Changed = false; DT.updateDFSNumbers(); @@ -577,6 +612,11 @@ // of constraints. if (CB.IsBlock) { for (Instruction &I : *CB.BB) { + + if (auto *II = dyn_cast(&I)) { + tryToSimplifyOverflowMath(II, Info); + continue; + } auto *Cmp = dyn_cast(&I); if (!Cmp) continue; diff --git a/llvm/test/Transforms/ConstraintElimination/ssub-with-overflow.ll b/llvm/test/Transforms/ConstraintElimination/ssub-with-overflow.ll --- a/llvm/test/Transforms/ConstraintElimination/ssub-with-overflow.ll +++ b/llvm/test/Transforms/ConstraintElimination/ssub-with-overflow.ll @@ -11,12 +11,13 @@ ; 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: [[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 ; @@ -47,12 +48,13 @@ ; CHECK-NEXT: [[AND:%.*]] = and i1 [[C_2]], [[C_1]] ; CHECK-NEXT: br i1 [[AND]], label [[MATH:%.*]], label [[EXIT_FAIL:%.*]] ; 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: [[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 ;