Index: lib/Transforms/Scalar/CorrelatedValuePropagation.cpp =================================================================== --- lib/Transforms/Scalar/CorrelatedValuePropagation.cpp +++ lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @@ -35,6 +35,7 @@ STATISTIC(NumCmps, "Number of comparisons propagated"); STATISTIC(NumReturns, "Number of return values propagated"); STATISTIC(NumDeadCases, "Number of switch cases removed"); +STATISTIC(NumSDivs, "Number of sdiv converted to udiv"); namespace { class CorrelatedValuePropagation : public FunctionPass { @@ -46,6 +47,7 @@ bool processCmp(CmpInst *C); bool processSwitch(SwitchInst *SI); bool processCallSite(CallSite CS); + bool processSDiv(BinaryOperator *SDI); /// Return a constant value for V usable at At and everything it /// dominates. If no such Constant can be found, return nullptr. @@ -337,6 +339,42 @@ return true; } +/// See if LazyValueInfo's ability to exploit edge conditions, or range +/// information is sufficient to prove the both operands of this SDiv are +/// nonnegative. If this is the case, replace the SDiv with a UDiv. Even for +/// local conditions, this can sometimes prove conditions instcombine can't by +/// exploiting range information. +bool CorrelatedValuePropagation::processSDiv(BinaryOperator *SDI) { + if (SDI->getType()->isVectorTy()) + return false; + + for (Value *O : SDI->operands()) { + // As a policy choice, we choose not to waste compile time on anything where + // the operands are local defs. While LVI can sometimes reason about such + // cases, it's not its primary purpose. + auto *I = dyn_cast(O); + if (I && I->getParent() == SDI->getParent()) + return false; + } + + Constant *Zero = ConstantInt::get(SDI->getType(), 0); + for (Value *O : SDI->operands()) { + LazyValueInfo::Tristate Result = + LVI->getPredicateAt(ICmpInst::ICMP_SGE, O, Zero, SDI); + if (Result != LazyValueInfo::True) + return false; + } + + ++NumSDivs; + auto *BO = BinaryOperator::CreateUDiv(SDI->getOperand(0), SDI->getOperand(1), + SDI->getName(), SDI); + BO->setIsExact(SDI->isExact()); + SDI->replaceAllUsesWith(BO); + SDI->eraseFromParent(); + + return true; +} + Constant *CorrelatedValuePropagation::getConstantAt(Value *V, Instruction *At) { if (Constant *C = LVI->getConstant(V, At->getParent(), At)) return C; @@ -391,6 +429,9 @@ case Instruction::Invoke: BBChanged |= processCallSite(CallSite(II)); break; + case Instruction::SDiv: + BBChanged |= processSDiv(cast(II)); + break; } } Index: test/Transforms/CorrelatedValuePropagation/sdiv.ll =================================================================== --- /dev/null +++ test/Transforms/CorrelatedValuePropagation/sdiv.ll @@ -0,0 +1,54 @@ +; RUN: opt < %s -correlated-propagation -S | FileCheck %s + +; CHECK-LABEL: @test0( +define void @test0(i32 %n) { +entry: + br label %for.cond + +for.cond: ; preds = %for.body, %entry + %j.0 = phi i32 [ %n, %entry ], [ %div, %for.body ] + %cmp = icmp sgt i32 %j.0, 1 + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond +; CHECK: %div1 = udiv i32 %j.0, 2 + %div = sdiv i32 %j.0, 2 + br label %for.cond + +for.end: ; preds = %for.cond + ret void +} + +; CHECK-LABEL: @test1( +define void @test1(i32 %n) { +entry: + br label %for.cond + +for.cond: ; preds = %for.body, %entry + %j.0 = phi i32 [ %n, %entry ], [ %div, %for.body ] + %cmp = icmp sgt i32 %j.0, -2 + br i1 %cmp, label %for.body, label %for.end + +for.body: ; preds = %for.cond +; CHECK: %div = sdiv i32 %j.0, 2 + %div = sdiv i32 %j.0, 2 + br label %for.cond + +for.end: ; preds = %for.cond + ret void +} + +; CHECK-LABEL: @test2( +define void @test2(i32 %n) { +entry: + %cmp = icmp sgt i32 %n, 1 + br i1 %cmp, label %bb, label %exit + +bb: +; CHECK: %div1 = udiv i32 %n, 2 + %div = sdiv i32 %n, 2 + br label %exit + +exit: + ret void +}