Skip to content

Commit

Permalink
[unroll] Use value domain for symbolic execution based cost model
Browse files Browse the repository at this point in the history
The current full unroll cost model does a symbolic evaluation of the loop up to a fixed limit. That symbolic evaluation currently simplifies to constants, but we can generalize to arbitrary Values using the InstructionSimplify infrastructure at very low cost.

By itself, this enables some simplifications, but it's mainly useful when combined with the branch simplification over in D102928.

Differential Revision: https://reviews.llvm.org/D102934
  • Loading branch information
preames committed May 26, 2021
1 parent 31191e1 commit 9cc2181
Show file tree
Hide file tree
Showing 5 changed files with 423 additions and 87 deletions.
7 changes: 2 additions & 5 deletions llvm/include/llvm/Analysis/LoopUnrollAnalyzer.h
Expand Up @@ -46,7 +46,7 @@ class UnrolledInstAnalyzer : private InstVisitor<UnrolledInstAnalyzer, bool> {

public:
UnrolledInstAnalyzer(unsigned Iteration,
DenseMap<Value *, Constant *> &SimplifiedValues,
DenseMap<Value *, Value *> &SimplifiedValues,
ScalarEvolution &SE, const Loop *L)
: SimplifiedValues(SimplifiedValues), SE(SE), L(L) {
IterationNumber = SE.getConstant(APInt(64, Iteration));
Expand All @@ -68,15 +68,12 @@ class UnrolledInstAnalyzer : private InstVisitor<UnrolledInstAnalyzer, bool> {
/// iteration.
const SCEV *IterationNumber;

/// A Value->Constant map for keeping values that we managed to
/// constant-fold on the given iteration.
///
/// While we walk the loop instructions, we build up and maintain a mapping
/// of simplified values specific to this iteration. The idea is to propagate
/// any special information we have about loads that can be replaced with
/// constants after complete unrolling, and account for likely simplifications
/// post-unrolling.
DenseMap<Value *, Constant *> &SimplifiedValues;
DenseMap<Value *, Value *> &SimplifiedValues;

ScalarEvolution &SE;
const Loop *L;
Expand Down
45 changes: 18 additions & 27 deletions llvm/lib/Analysis/LoopUnrollAnalyzer.cpp
Expand Up @@ -74,10 +74,10 @@ bool UnrolledInstAnalyzer::simplifyInstWithSCEV(Instruction *I) {
bool UnrolledInstAnalyzer::visitBinaryOperator(BinaryOperator &I) {
Value *LHS = I.getOperand(0), *RHS = I.getOperand(1);
if (!isa<Constant>(LHS))
if (Constant *SimpleLHS = SimplifiedValues.lookup(LHS))
if (Value *SimpleLHS = SimplifiedValues.lookup(LHS))
LHS = SimpleLHS;
if (!isa<Constant>(RHS))
if (Constant *SimpleRHS = SimplifiedValues.lookup(RHS))
if (Value *SimpleRHS = SimplifiedValues.lookup(RHS))
RHS = SimpleRHS;

Value *SimpleV = nullptr;
Expand All @@ -88,11 +88,10 @@ bool UnrolledInstAnalyzer::visitBinaryOperator(BinaryOperator &I) {
else
SimpleV = SimplifyBinOp(I.getOpcode(), LHS, RHS, DL);

if (Constant *C = dyn_cast_or_null<Constant>(SimpleV))
SimplifiedValues[&I] = C;

if (SimpleV)
if (SimpleV) {
SimplifiedValues[&I] = SimpleV;
return true;
}
return Base::visitBinaryOperator(I);
}

Expand Down Expand Up @@ -147,20 +146,17 @@ bool UnrolledInstAnalyzer::visitLoad(LoadInst &I) {

/// Try to simplify cast instruction.
bool UnrolledInstAnalyzer::visitCastInst(CastInst &I) {
// Propagate constants through casts.
Constant *COp = dyn_cast<Constant>(I.getOperand(0));
if (!COp)
COp = SimplifiedValues.lookup(I.getOperand(0));
Value *Op = I.getOperand(0);
if (Value *Simplified = SimplifiedValues.lookup(Op))
Op = Simplified;

// If we know a simplified value for this operand and cast is valid, save the
// result to SimplifiedValues.
// The cast can be invalid, because SimplifiedValues contains results of SCEV
// analysis, which operates on integers (and, e.g., might convert i8* null to
// i32 0).
if (COp && CastInst::castIsValid(I.getOpcode(), COp, I.getType())) {
if (Constant *C =
ConstantExpr::getCast(I.getOpcode(), COp, I.getType())) {
SimplifiedValues[&I] = C;
if (CastInst::castIsValid(I.getOpcode(), Op, I.getType())) {
const DataLayout &DL = I.getModule()->getDataLayout();
if (Value *V = SimplifyCastInst(I.getOpcode(), Op, I.getType(), DL)) {
SimplifiedValues[&I] = V;
return true;
}
}
Expand All @@ -174,10 +170,10 @@ bool UnrolledInstAnalyzer::visitCmpInst(CmpInst &I) {

// First try to handle simplified comparisons.
if (!isa<Constant>(LHS))
if (Constant *SimpleLHS = SimplifiedValues.lookup(LHS))
if (Value *SimpleLHS = SimplifiedValues.lookup(LHS))
LHS = SimpleLHS;
if (!isa<Constant>(RHS))
if (Constant *SimpleRHS = SimplifiedValues.lookup(RHS))
if (Value *SimpleRHS = SimplifiedValues.lookup(RHS))
RHS = SimpleRHS;

if (!isa<Constant>(LHS) && !isa<Constant>(RHS)) {
Expand All @@ -195,15 +191,10 @@ bool UnrolledInstAnalyzer::visitCmpInst(CmpInst &I) {
}
}

if (Constant *CLHS = dyn_cast<Constant>(LHS)) {
if (Constant *CRHS = dyn_cast<Constant>(RHS)) {
if (CLHS->getType() == CRHS->getType()) {
if (Constant *C = ConstantExpr::getCompare(I.getPredicate(), CLHS, CRHS)) {
SimplifiedValues[&I] = C;
return true;
}
}
}
const DataLayout &DL = I.getModule()->getDataLayout();
if (Value *V = SimplifyCmpInst(I.getPredicate(), LHS, RHS, DL)) {
SimplifiedValues[&I] = V;
return true;
}

return Base::visitCmpInst(I);
Expand Down
24 changes: 13 additions & 11 deletions llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp
Expand Up @@ -356,8 +356,8 @@ static Optional<EstimatedUnrollCost> analyzeLoopUnrollCost(

SmallSetVector<BasicBlock *, 16> BBWorklist;
SmallSetVector<std::pair<BasicBlock *, BasicBlock *>, 4> ExitWorklist;
DenseMap<Value *, Constant *> SimplifiedValues;
SmallVector<std::pair<Value *, Constant *>, 4> SimplifiedInputValues;
DenseMap<Value *, Value *> SimplifiedValues;
SmallVector<std::pair<Value *, Value *>, 4> SimplifiedInputValues;

// The estimated cost of the unrolled form of the loop. We try to estimate
// this by simplifying as much as we can while computing the estimate.
Expand Down Expand Up @@ -498,11 +498,9 @@ static Optional<EstimatedUnrollCost> analyzeLoopUnrollCost(

Value *V = PHI->getIncomingValueForBlock(
Iteration == 0 ? L->getLoopPreheader() : L->getLoopLatch());
Constant *C = dyn_cast<Constant>(V);
if (Iteration != 0 && !C)
C = SimplifiedValues.lookup(V);
if (C)
SimplifiedInputValues.push_back({PHI, C});
if (Iteration != 0 && SimplifiedValues.count(V))
V = SimplifiedValues.lookup(V);
SimplifiedInputValues.push_back({PHI, V});
}

// Now clear and re-populate the map for the next iteration.
Expand Down Expand Up @@ -571,13 +569,18 @@ static Optional<EstimatedUnrollCost> analyzeLoopUnrollCost(

Instruction *TI = BB->getTerminator();

auto getSimplifiedConstant = [&](Value *V) -> Constant * {
if (SimplifiedValues.count(V))
V = SimplifiedValues.lookup(V);
return dyn_cast<Constant>(V);
};

// Add in the live successors by first checking whether we have terminator
// that may be simplified based on the values simplified by this call.
BasicBlock *KnownSucc = nullptr;
if (BranchInst *BI = dyn_cast<BranchInst>(TI)) {
if (BI->isConditional()) {
if (Constant *SimpleCond =
SimplifiedValues.lookup(BI->getCondition())) {
if (auto *SimpleCond = getSimplifiedConstant(BI->getCondition())) {
// Just take the first successor if condition is undef
if (isa<UndefValue>(SimpleCond))
KnownSucc = BI->getSuccessor(0);
Expand All @@ -587,8 +590,7 @@ static Optional<EstimatedUnrollCost> analyzeLoopUnrollCost(
}
}
} else if (SwitchInst *SI = dyn_cast<SwitchInst>(TI)) {
if (Constant *SimpleCond =
SimplifiedValues.lookup(SI->getCondition())) {
if (auto *SimpleCond = getSimplifiedConstant(SI->getCondition())) {
// Just take the first successor if condition is undef
if (isa<UndefValue>(SimpleCond))
KnownSucc = SI->getSuccessor(0);
Expand Down

0 comments on commit 9cc2181

Please sign in to comment.