summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp41
-rw-r--r--llvm/test/Transforms/CorrelatedValuePropagation/sdiv.ll54
2 files changed, 95 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
index 56b23733315..046d3791a19 100644
--- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
+++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
@@ -35,6 +35,7 @@ STATISTIC(NumMemAccess, "Number of memory access targets propagated");
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 @@ namespace {
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 @@ bool CorrelatedValuePropagation::processCallSite(CallSite CS) {
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<Instruction>(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 @@ bool CorrelatedValuePropagation::runOnFunction(Function &F) {
case Instruction::Invoke:
BBChanged |= processCallSite(CallSite(II));
break;
+ case Instruction::SDiv:
+ BBChanged |= processSDiv(cast<BinaryOperator>(II));
+ break;
}
}
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/sdiv.ll b/llvm/test/Transforms/CorrelatedValuePropagation/sdiv.ll
new file mode 100644
index 00000000000..3d785785d35
--- /dev/null
+++ b/llvm/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
+}
OpenPOWER on IntegriCloud