[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
llvm-svn: 363489
diff --git a/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp b/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp
index f1048d9..cbb114f 100644
--- a/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp
@@ -81,6 +81,7 @@
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 @@
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 <pred> i32 trunc(iv), n
@@ -614,6 +634,10 @@
if (eliminateOverflowIntrinsic(WO))
return true;
+ if (auto *SI = dyn_cast<SaturatingInst>(UseInst))
+ if (eliminateSaturatingIntrinsic(SI))
+ return true;
+
if (auto *TI = dyn_cast<TruncInst>(UseInst))
if (eliminateTrunc(TI))
return true;
diff --git a/llvm/test/Transforms/IndVarSimplify/eliminate-sat.ll b/llvm/test/Transforms/IndVarSimplify/eliminate-sat.ll
index b7c3804..1b3eb69 100644
--- a/llvm/test/Transforms/IndVarSimplify/eliminate-sat.ll
+++ b/llvm/test/Transforms/IndVarSimplify/eliminate-sat.ll
@@ -12,8 +12,8 @@
; 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 @@
; 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 @@
; 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 @@
; 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:%.*]]