From bf4a9f732581a6e85a904a7b3b612b658860ca7e Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sat, 15 Jun 2019 08:48:52 +0000 Subject: [PATCH] [SimplifyIndVar] Simplify non-overflowing saturating add/sub If we can detect that saturating math that depends on an IV cannot overflow, replace it with simple math. This is similar to the CVP optimization from D62703, just based on a different underlying analysis (SCEV vs LVI) that catches different cases. Differential Revision: https://reviews.llvm.org/D62792 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@363489 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Transforms/Utils/SimplifyIndVar.cpp | 24 +++++++++++++++++++ .../IndVarSimplify/eliminate-sat.ll | 16 ++++++------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/lib/Transforms/Utils/SimplifyIndVar.cpp b/lib/Transforms/Utils/SimplifyIndVar.cpp index f1048d98f00..cbb114f9a47 100644 --- a/lib/Transforms/Utils/SimplifyIndVar.cpp +++ b/lib/Transforms/Utils/SimplifyIndVar.cpp @@ -81,6 +81,7 @@ namespace { bool replaceIVUserWithLoopInvariant(Instruction *UseInst); bool eliminateOverflowIntrinsic(WithOverflowInst *WO); + bool eliminateSaturatingIntrinsic(SaturatingInst *SI); bool eliminateTrunc(TruncInst *TI); bool eliminateIVUser(Instruction *UseInst, Instruction *IVOperand); bool makeIVComparisonInvariant(ICmpInst *ICmp, Value *IVOperand); @@ -477,6 +478,25 @@ bool SimplifyIndvar::eliminateOverflowIntrinsic(WithOverflowInst *WO) { return true; } +bool SimplifyIndvar::eliminateSaturatingIntrinsic(SaturatingInst *SI) { + const SCEV *LHS = SE->getSCEV(SI->getLHS()); + const SCEV *RHS = SE->getSCEV(SI->getRHS()); + if (!willNotOverflow(SE, SI->getBinaryOp(), SI->isSigned(), LHS, RHS)) + return false; + + BinaryOperator *BO = BinaryOperator::Create( + SI->getBinaryOp(), SI->getLHS(), SI->getRHS(), SI->getName(), SI); + if (SI->isSigned()) + BO->setHasNoSignedWrap(); + else + BO->setHasNoUnsignedWrap(); + + SI->replaceAllUsesWith(BO); + DeadInsts.emplace_back(SI); + Changed = true; + return true; +} + bool SimplifyIndvar::eliminateTrunc(TruncInst *TI) { // It is always legal to replace // icmp i32 trunc(iv), n @@ -614,6 +634,10 @@ bool SimplifyIndvar::eliminateIVUser(Instruction *UseInst, if (eliminateOverflowIntrinsic(WO)) return true; + if (auto *SI = dyn_cast(UseInst)) + if (eliminateSaturatingIntrinsic(SI)) + return true; + if (auto *TI = dyn_cast(UseInst)) if (eliminateTrunc(TI)) return true; diff --git a/test/Transforms/IndVarSimplify/eliminate-sat.ll b/test/Transforms/IndVarSimplify/eliminate-sat.ll index b7c38041040..1b3eb69d01f 100644 --- a/test/Transforms/IndVarSimplify/eliminate-sat.ll +++ b/test/Transforms/IndVarSimplify/eliminate-sat.ll @@ -12,8 +12,8 @@ define void @uadd_sat(i32* %p) { ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[SAT:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[I]], i32 1) -; CHECK-NEXT: store volatile i32 [[SAT]], i32* [[P:%.*]] +; CHECK-NEXT: [[SAT1:%.*]] = add nuw nsw i32 [[I]], 1 +; CHECK-NEXT: store volatile i32 [[SAT1]], i32* [[P:%.*]] ; CHECK-NEXT: [[I_INC]] = add nuw nsw i32 [[I]], 1 ; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[I_INC]], 100 ; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[END:%.*]] @@ -41,8 +41,8 @@ define void @sadd_sat(i32* %p) { ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[SAT:%.*]] = call i32 @llvm.sadd.sat.i32(i32 [[I]], i32 1) -; CHECK-NEXT: store volatile i32 [[SAT]], i32* [[P:%.*]] +; CHECK-NEXT: [[SAT1:%.*]] = add nuw nsw i32 [[I]], 1 +; CHECK-NEXT: store volatile i32 [[SAT1]], i32* [[P:%.*]] ; CHECK-NEXT: [[I_INC]] = add nuw nsw i32 [[I]], 1 ; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[I_INC]], 100 ; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[END:%.*]] @@ -70,8 +70,8 @@ define void @usub_sat(i32* %p) { ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[I:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[SAT:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[I]], i32 1) -; CHECK-NEXT: store volatile i32 [[SAT]], i32* [[P:%.*]] +; CHECK-NEXT: [[SAT1:%.*]] = sub nuw nsw i32 [[I]], 1 +; CHECK-NEXT: store volatile i32 [[SAT1]], i32* [[P:%.*]] ; CHECK-NEXT: [[I_INC]] = add nuw nsw i32 [[I]], 1 ; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[I_INC]], 100 ; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[END:%.*]] @@ -99,8 +99,8 @@ define void @ssub_sat(i32* %p) { ; CHECK-NEXT: br label [[LOOP:%.*]] ; CHECK: loop: ; CHECK-NEXT: [[I:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[I_INC:%.*]], [[LOOP]] ] -; CHECK-NEXT: [[SAT:%.*]] = call i32 @llvm.ssub.sat.i32(i32 [[I]], i32 1) -; CHECK-NEXT: store volatile i32 [[SAT]], i32* [[P:%.*]] +; CHECK-NEXT: [[SAT1:%.*]] = sub nsw i32 [[I]], 1 +; CHECK-NEXT: store volatile i32 [[SAT1]], i32* [[P:%.*]] ; CHECK-NEXT: [[I_INC]] = add nuw nsw i32 [[I]], 1 ; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[I_INC]], 100 ; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[END:%.*]] -- 2.40.0