Index: lib/Transforms/Utils/SimplifyIndVar.cpp =================================================================== --- lib/Transforms/Utils/SimplifyIndVar.cpp +++ lib/Transforms/Utils/SimplifyIndVar.cpp @@ -35,6 +35,7 @@ STATISTIC(NumElimIdentity, "Number of IV identities eliminated"); STATISTIC(NumElimOperand, "Number of IV operands folded into a use"); STATISTIC(NumElimRem , "Number of IV remainder operations eliminated"); +STATISTIC(NumElimSDiv , "Number of IV signed division operations eliminated"); STATISTIC(NumElimCmp , "Number of IV comparisons eliminated"); namespace { @@ -75,6 +76,7 @@ void eliminateIVComparison(ICmpInst *ICmp, Value *IVOperand); void eliminateIVRemainder(BinaryOperator *Rem, Value *IVOperand, bool IsSigned); + bool eliminateSDiv(BinaryOperator *SDiv, Value *IVOperand); bool strengthenOverflowingOperation(BinaryOperator *OBO, Value *IVOperand); }; } @@ -265,6 +267,39 @@ Changed = true; } +/// SimplifyIVUsers helper for replacing signed division operations operating on +/// an induction variable. +bool SimplifyIndvar::eliminateSDiv(BinaryOperator *SDiv, Value *IVOperand) { + // We're only interested in the case where we know something about + // the numerator. + if (IVOperand != SDiv->getOperand(0)) + return false; + + // Get the SCEVs for the ICmp operands. + auto S = SE->getSCEV(SDiv->getOperand(0)); + auto X = SE->getSCEV(SDiv->getOperand(1)); + + // Simplify unnecessary loops away. + const Loop *L = LI->getLoopFor(SDiv->getParent()); + S = SE->getSCEVAtScope(S, L); + X = SE->getSCEVAtScope(X, L); + + // Replace sdiv by udiv if both of the operands are non-negative + if (SE->isKnownNonNegative(S) && SE->isKnownNonNegative(X)) { + auto UDiv = BinaryOperator::Create( + BinaryOperator::UDiv, SDiv->getOperand(0), SDiv->getOperand(1), + SDiv->getName() + ".udiv", SDiv); + SDiv->replaceAllUsesWith(UDiv); + DEBUG(dbgs() << "INDVARS: Simplified sdiv: " << *SDiv << '\n'); + ++NumElimSDiv; + Changed = true; + DeadInsts.emplace_back(SDiv); + return true; + } + + return false; +} + /// SimplifyIVUsers helper for eliminating useless /// remainder operations operating on an induction variable. void SimplifyIndvar::eliminateIVRemainder(BinaryOperator *Rem, @@ -426,12 +461,15 @@ eliminateIVComparison(ICmp, IVOperand); return true; } - if (BinaryOperator *Rem = dyn_cast(UseInst)) { - bool IsSigned = Rem->getOpcode() == Instruction::SRem; - if (IsSigned || Rem->getOpcode() == Instruction::URem) { - eliminateIVRemainder(Rem, IVOperand, IsSigned); + if (BinaryOperator *Bin = dyn_cast(UseInst)) { + bool IsSRem = Bin->getOpcode() == Instruction::SRem; + if (IsSRem || Bin->getOpcode() == Instruction::URem) { + eliminateIVRemainder(Bin, IVOperand, IsSRem); return true; } + + if (Bin->getOpcode() == Instruction::SDiv) + return eliminateSDiv(Bin, IVOperand); } if (auto *CI = dyn_cast(UseInst)) Index: test/Transforms/IndVarSimplify/replace-sdiv-by-udiv.ll =================================================================== --- /dev/null +++ test/Transforms/IndVarSimplify/replace-sdiv-by-udiv.ll @@ -0,0 +1,23 @@ +; RUN: opt < %s -indvars -S | FileCheck %s + +define void @test(i32* %a) { +; CHECK-LABEL: @test( +entry: + br label %for.body + +for.body: ; preds = %entry, %for.body + %i.01 = phi i32 [ 0, %entry ], [ %inc, %for.body ] + %mul = mul nsw i32 %i.01, 64 + %div = sdiv i32 %mul, 2 +; CHECK-NOT: sdiv +; CHECK: udiv + %idxprom = sext i32 %div to i64 + %arrayidx = getelementptr inbounds i32, i32* %a, i64 %idxprom + store i32 %i.01, i32* %arrayidx, align 4 + %inc = add nsw i32 %i.01, 1 + %cmp = icmp slt i32 %inc, 64 + br i1 %cmp, label %for.body, label %for.end + +for.end: ; preds = %for.body + ret void +}