Index: llvm/lib/Transforms/Utils/SimplifyIndVar.cpp =================================================================== --- llvm/lib/Transforms/Utils/SimplifyIndVar.cpp +++ 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 i32 trunc(iv), n @@ -613,6 +633,10 @@ 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; Index: llvm/test/Transforms/IndVarSimplify/eliminate-sat.ll =================================================================== --- llvm/test/Transforms/IndVarSimplify/eliminate-sat.ll +++ 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:%.*]]