[llvm] r363489 - [SimplifyIndVar] Simplify non-overflowing saturating add/sub

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 15 01:48:52 PDT 2019


Author: nikic
Date: Sat Jun 15 01:48:52 2019
New Revision: 363489

URL: http://llvm.org/viewvc/llvm-project?rev=363489&view=rev
Log:
[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

Modified:
    llvm/trunk/lib/Transforms/Utils/SimplifyIndVar.cpp
    llvm/trunk/test/Transforms/IndVarSimplify/eliminate-sat.ll

Modified: llvm/trunk/lib/Transforms/Utils/SimplifyIndVar.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/SimplifyIndVar.cpp?rev=363489&r1=363488&r2=363489&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/SimplifyIndVar.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/SimplifyIndVar.cpp Sat Jun 15 01:48:52 2019
@@ -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::eliminateOverflowIn
   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 @@ bool SimplifyIndvar::eliminateIVUser(Ins
     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;

Modified: llvm/trunk/test/Transforms/IndVarSimplify/eliminate-sat.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/IndVarSimplify/eliminate-sat.ll?rev=363489&r1=363488&r2=363489&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/IndVarSimplify/eliminate-sat.ll (original)
+++ llvm/trunk/test/Transforms/IndVarSimplify/eliminate-sat.ll Sat Jun 15 01:48:52 2019
@@ -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:%.*]]




More information about the llvm-commits mailing list