1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 04:02:41 +01:00

[unroll] Use value domain for symbolic execution based cost model

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
This commit is contained in:
Philip Reames 2021-05-26 08:40:01 -07:00
parent 0a9439773a
commit 88bae72814
5 changed files with 423 additions and 87 deletions

View File

@ -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));
@ -68,15 +68,12 @@ private:
/// 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;

View File

@ -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;
@ -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);
}
@ -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;
}
}
@ -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)) {
@ -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);

View File

@ -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.
@ -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.
@ -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);
@ -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);

View File

@ -12,37 +12,250 @@
define i32 @test_symbolic_simplify(i32 %limit) {
; CHECK-LABEL: @test_symbolic_simplify(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP_PEEL_BEGIN:%.*]]
; CHECK: loop.peel.begin:
; CHECK-NEXT: br label [[LOOP_PEEL:%.*]]
; CHECK: loop.peel:
; CHECK-NEXT: [[SUB_PEEL:%.*]] = sub i32 [[LIMIT:%.*]], 0
; CHECK-NEXT: [[CMP_PEEL:%.*]] = icmp eq i32 [[SUB_PEEL]], [[LIMIT]]
; CHECK-NEXT: [[ZEXT_PEEL:%.*]] = sext i1 [[CMP_PEEL]] to i32
; CHECK-NEXT: store i32 [[ZEXT_PEEL]], i32* @G, align 4
; CHECK-NEXT: [[IV_NEXT_PEEL:%.*]] = add i32 0, 1
; CHECK-NEXT: [[LOOP_COND_PEEL:%.*]] = icmp ne i32 0, 80
; CHECK-NEXT: br i1 [[LOOP_COND_PEEL]], label [[LOOP_PEEL_NEXT:%.*]], label [[DONE:%.*]]
; CHECK: loop.peel.next:
; CHECK-NEXT: br label [[LOOP_PEEL_NEXT1:%.*]]
; CHECK: loop.peel.next1:
; CHECK-NEXT: br label [[ENTRY_PEEL_NEWPH:%.*]]
; CHECK: entry.peel.newph:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ [[IV_NEXT_PEEL]], [[ENTRY_PEEL_NEWPH]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT:%.*]] = sext i1 [[CMP]] to i32
; CHECK-NEXT: store i32 [[ZEXT]], i32* @G, align 4
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ne i32 [[IV]], 80
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[DONE_LOOPEXIT:%.*]], !llvm.loop [[LOOP0:![0-9]+]]
; CHECK: done.loopexit:
; CHECK-NEXT: [[ZEXT_LCSSA_PH:%.*]] = phi i32 [ [[ZEXT]], [[LOOP]] ]
; CHECK-NEXT: br label [[DONE]]
; CHECK: done:
; CHECK-NEXT: [[ZEXT_LCSSA:%.*]] = phi i32 [ [[ZEXT_PEEL]], [[LOOP_PEEL]] ], [ [[ZEXT_LCSSA_PH]], [[DONE_LOOPEXIT]] ]
; CHECK-NEXT: ret i32 [[ZEXT_LCSSA]]
; CHECK-NEXT: store i32 -1, i32* @G, align 4
; CHECK-NEXT: [[CMP_1:%.*]] = icmp eq i32 0, [[LIMIT:%.*]]
; CHECK-NEXT: [[ZEXT_1:%.*]] = sext i1 [[CMP_1]] to i32
; CHECK-NEXT: store i32 [[ZEXT_1]], i32* @G, align 4
; CHECK-NEXT: [[CMP_2:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_2:%.*]] = sext i1 [[CMP_2]] to i32
; CHECK-NEXT: store i32 [[ZEXT_2]], i32* @G, align 4
; CHECK-NEXT: [[CMP_3:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_3:%.*]] = sext i1 [[CMP_3]] to i32
; CHECK-NEXT: store i32 [[ZEXT_3]], i32* @G, align 4
; CHECK-NEXT: [[CMP_4:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_4:%.*]] = sext i1 [[CMP_4]] to i32
; CHECK-NEXT: store i32 [[ZEXT_4]], i32* @G, align 4
; CHECK-NEXT: [[CMP_5:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_5:%.*]] = sext i1 [[CMP_5]] to i32
; CHECK-NEXT: store i32 [[ZEXT_5]], i32* @G, align 4
; CHECK-NEXT: [[CMP_6:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_6:%.*]] = sext i1 [[CMP_6]] to i32
; CHECK-NEXT: store i32 [[ZEXT_6]], i32* @G, align 4
; CHECK-NEXT: [[CMP_7:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_7:%.*]] = sext i1 [[CMP_7]] to i32
; CHECK-NEXT: store i32 [[ZEXT_7]], i32* @G, align 4
; CHECK-NEXT: [[CMP_8:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_8:%.*]] = sext i1 [[CMP_8]] to i32
; CHECK-NEXT: store i32 [[ZEXT_8]], i32* @G, align 4
; CHECK-NEXT: [[CMP_9:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_9:%.*]] = sext i1 [[CMP_9]] to i32
; CHECK-NEXT: store i32 [[ZEXT_9]], i32* @G, align 4
; CHECK-NEXT: [[CMP_10:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_10:%.*]] = sext i1 [[CMP_10]] to i32
; CHECK-NEXT: store i32 [[ZEXT_10]], i32* @G, align 4
; CHECK-NEXT: [[CMP_11:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_11:%.*]] = sext i1 [[CMP_11]] to i32
; CHECK-NEXT: store i32 [[ZEXT_11]], i32* @G, align 4
; CHECK-NEXT: [[CMP_12:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_12:%.*]] = sext i1 [[CMP_12]] to i32
; CHECK-NEXT: store i32 [[ZEXT_12]], i32* @G, align 4
; CHECK-NEXT: [[CMP_13:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_13:%.*]] = sext i1 [[CMP_13]] to i32
; CHECK-NEXT: store i32 [[ZEXT_13]], i32* @G, align 4
; CHECK-NEXT: [[CMP_14:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_14:%.*]] = sext i1 [[CMP_14]] to i32
; CHECK-NEXT: store i32 [[ZEXT_14]], i32* @G, align 4
; CHECK-NEXT: [[CMP_15:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_15:%.*]] = sext i1 [[CMP_15]] to i32
; CHECK-NEXT: store i32 [[ZEXT_15]], i32* @G, align 4
; CHECK-NEXT: [[CMP_16:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_16:%.*]] = sext i1 [[CMP_16]] to i32
; CHECK-NEXT: store i32 [[ZEXT_16]], i32* @G, align 4
; CHECK-NEXT: [[CMP_17:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_17:%.*]] = sext i1 [[CMP_17]] to i32
; CHECK-NEXT: store i32 [[ZEXT_17]], i32* @G, align 4
; CHECK-NEXT: [[CMP_18:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_18:%.*]] = sext i1 [[CMP_18]] to i32
; CHECK-NEXT: store i32 [[ZEXT_18]], i32* @G, align 4
; CHECK-NEXT: [[CMP_19:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_19:%.*]] = sext i1 [[CMP_19]] to i32
; CHECK-NEXT: store i32 [[ZEXT_19]], i32* @G, align 4
; CHECK-NEXT: [[CMP_20:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_20:%.*]] = sext i1 [[CMP_20]] to i32
; CHECK-NEXT: store i32 [[ZEXT_20]], i32* @G, align 4
; CHECK-NEXT: [[CMP_21:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_21:%.*]] = sext i1 [[CMP_21]] to i32
; CHECK-NEXT: store i32 [[ZEXT_21]], i32* @G, align 4
; CHECK-NEXT: [[CMP_22:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_22:%.*]] = sext i1 [[CMP_22]] to i32
; CHECK-NEXT: store i32 [[ZEXT_22]], i32* @G, align 4
; CHECK-NEXT: [[CMP_23:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_23:%.*]] = sext i1 [[CMP_23]] to i32
; CHECK-NEXT: store i32 [[ZEXT_23]], i32* @G, align 4
; CHECK-NEXT: [[CMP_24:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_24:%.*]] = sext i1 [[CMP_24]] to i32
; CHECK-NEXT: store i32 [[ZEXT_24]], i32* @G, align 4
; CHECK-NEXT: [[CMP_25:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_25:%.*]] = sext i1 [[CMP_25]] to i32
; CHECK-NEXT: store i32 [[ZEXT_25]], i32* @G, align 4
; CHECK-NEXT: [[CMP_26:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_26:%.*]] = sext i1 [[CMP_26]] to i32
; CHECK-NEXT: store i32 [[ZEXT_26]], i32* @G, align 4
; CHECK-NEXT: [[CMP_27:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_27:%.*]] = sext i1 [[CMP_27]] to i32
; CHECK-NEXT: store i32 [[ZEXT_27]], i32* @G, align 4
; CHECK-NEXT: [[CMP_28:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_28:%.*]] = sext i1 [[CMP_28]] to i32
; CHECK-NEXT: store i32 [[ZEXT_28]], i32* @G, align 4
; CHECK-NEXT: [[CMP_29:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_29:%.*]] = sext i1 [[CMP_29]] to i32
; CHECK-NEXT: store i32 [[ZEXT_29]], i32* @G, align 4
; CHECK-NEXT: [[CMP_30:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_30:%.*]] = sext i1 [[CMP_30]] to i32
; CHECK-NEXT: store i32 [[ZEXT_30]], i32* @G, align 4
; CHECK-NEXT: [[CMP_31:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_31:%.*]] = sext i1 [[CMP_31]] to i32
; CHECK-NEXT: store i32 [[ZEXT_31]], i32* @G, align 4
; CHECK-NEXT: [[CMP_32:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_32:%.*]] = sext i1 [[CMP_32]] to i32
; CHECK-NEXT: store i32 [[ZEXT_32]], i32* @G, align 4
; CHECK-NEXT: [[CMP_33:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_33:%.*]] = sext i1 [[CMP_33]] to i32
; CHECK-NEXT: store i32 [[ZEXT_33]], i32* @G, align 4
; CHECK-NEXT: [[CMP_34:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_34:%.*]] = sext i1 [[CMP_34]] to i32
; CHECK-NEXT: store i32 [[ZEXT_34]], i32* @G, align 4
; CHECK-NEXT: [[CMP_35:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_35:%.*]] = sext i1 [[CMP_35]] to i32
; CHECK-NEXT: store i32 [[ZEXT_35]], i32* @G, align 4
; CHECK-NEXT: [[CMP_36:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_36:%.*]] = sext i1 [[CMP_36]] to i32
; CHECK-NEXT: store i32 [[ZEXT_36]], i32* @G, align 4
; CHECK-NEXT: [[CMP_37:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_37:%.*]] = sext i1 [[CMP_37]] to i32
; CHECK-NEXT: store i32 [[ZEXT_37]], i32* @G, align 4
; CHECK-NEXT: [[CMP_38:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_38:%.*]] = sext i1 [[CMP_38]] to i32
; CHECK-NEXT: store i32 [[ZEXT_38]], i32* @G, align 4
; CHECK-NEXT: [[CMP_39:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_39:%.*]] = sext i1 [[CMP_39]] to i32
; CHECK-NEXT: store i32 [[ZEXT_39]], i32* @G, align 4
; CHECK-NEXT: [[CMP_40:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_40:%.*]] = sext i1 [[CMP_40]] to i32
; CHECK-NEXT: store i32 [[ZEXT_40]], i32* @G, align 4
; CHECK-NEXT: [[CMP_41:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_41:%.*]] = sext i1 [[CMP_41]] to i32
; CHECK-NEXT: store i32 [[ZEXT_41]], i32* @G, align 4
; CHECK-NEXT: [[CMP_42:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_42:%.*]] = sext i1 [[CMP_42]] to i32
; CHECK-NEXT: store i32 [[ZEXT_42]], i32* @G, align 4
; CHECK-NEXT: [[CMP_43:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_43:%.*]] = sext i1 [[CMP_43]] to i32
; CHECK-NEXT: store i32 [[ZEXT_43]], i32* @G, align 4
; CHECK-NEXT: [[CMP_44:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_44:%.*]] = sext i1 [[CMP_44]] to i32
; CHECK-NEXT: store i32 [[ZEXT_44]], i32* @G, align 4
; CHECK-NEXT: [[CMP_45:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_45:%.*]] = sext i1 [[CMP_45]] to i32
; CHECK-NEXT: store i32 [[ZEXT_45]], i32* @G, align 4
; CHECK-NEXT: [[CMP_46:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_46:%.*]] = sext i1 [[CMP_46]] to i32
; CHECK-NEXT: store i32 [[ZEXT_46]], i32* @G, align 4
; CHECK-NEXT: [[CMP_47:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_47:%.*]] = sext i1 [[CMP_47]] to i32
; CHECK-NEXT: store i32 [[ZEXT_47]], i32* @G, align 4
; CHECK-NEXT: [[CMP_48:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_48:%.*]] = sext i1 [[CMP_48]] to i32
; CHECK-NEXT: store i32 [[ZEXT_48]], i32* @G, align 4
; CHECK-NEXT: [[CMP_49:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_49:%.*]] = sext i1 [[CMP_49]] to i32
; CHECK-NEXT: store i32 [[ZEXT_49]], i32* @G, align 4
; CHECK-NEXT: [[CMP_50:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_50:%.*]] = sext i1 [[CMP_50]] to i32
; CHECK-NEXT: store i32 [[ZEXT_50]], i32* @G, align 4
; CHECK-NEXT: [[CMP_51:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_51:%.*]] = sext i1 [[CMP_51]] to i32
; CHECK-NEXT: store i32 [[ZEXT_51]], i32* @G, align 4
; CHECK-NEXT: [[CMP_52:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_52:%.*]] = sext i1 [[CMP_52]] to i32
; CHECK-NEXT: store i32 [[ZEXT_52]], i32* @G, align 4
; CHECK-NEXT: [[CMP_53:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_53:%.*]] = sext i1 [[CMP_53]] to i32
; CHECK-NEXT: store i32 [[ZEXT_53]], i32* @G, align 4
; CHECK-NEXT: [[CMP_54:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_54:%.*]] = sext i1 [[CMP_54]] to i32
; CHECK-NEXT: store i32 [[ZEXT_54]], i32* @G, align 4
; CHECK-NEXT: [[CMP_55:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_55:%.*]] = sext i1 [[CMP_55]] to i32
; CHECK-NEXT: store i32 [[ZEXT_55]], i32* @G, align 4
; CHECK-NEXT: [[CMP_56:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_56:%.*]] = sext i1 [[CMP_56]] to i32
; CHECK-NEXT: store i32 [[ZEXT_56]], i32* @G, align 4
; CHECK-NEXT: [[CMP_57:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_57:%.*]] = sext i1 [[CMP_57]] to i32
; CHECK-NEXT: store i32 [[ZEXT_57]], i32* @G, align 4
; CHECK-NEXT: [[CMP_58:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_58:%.*]] = sext i1 [[CMP_58]] to i32
; CHECK-NEXT: store i32 [[ZEXT_58]], i32* @G, align 4
; CHECK-NEXT: [[CMP_59:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_59:%.*]] = sext i1 [[CMP_59]] to i32
; CHECK-NEXT: store i32 [[ZEXT_59]], i32* @G, align 4
; CHECK-NEXT: [[CMP_60:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_60:%.*]] = sext i1 [[CMP_60]] to i32
; CHECK-NEXT: store i32 [[ZEXT_60]], i32* @G, align 4
; CHECK-NEXT: [[CMP_61:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_61:%.*]] = sext i1 [[CMP_61]] to i32
; CHECK-NEXT: store i32 [[ZEXT_61]], i32* @G, align 4
; CHECK-NEXT: [[CMP_62:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_62:%.*]] = sext i1 [[CMP_62]] to i32
; CHECK-NEXT: store i32 [[ZEXT_62]], i32* @G, align 4
; CHECK-NEXT: [[CMP_63:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_63:%.*]] = sext i1 [[CMP_63]] to i32
; CHECK-NEXT: store i32 [[ZEXT_63]], i32* @G, align 4
; CHECK-NEXT: [[CMP_64:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_64:%.*]] = sext i1 [[CMP_64]] to i32
; CHECK-NEXT: store i32 [[ZEXT_64]], i32* @G, align 4
; CHECK-NEXT: [[CMP_65:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_65:%.*]] = sext i1 [[CMP_65]] to i32
; CHECK-NEXT: store i32 [[ZEXT_65]], i32* @G, align 4
; CHECK-NEXT: [[CMP_66:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_66:%.*]] = sext i1 [[CMP_66]] to i32
; CHECK-NEXT: store i32 [[ZEXT_66]], i32* @G, align 4
; CHECK-NEXT: [[CMP_67:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_67:%.*]] = sext i1 [[CMP_67]] to i32
; CHECK-NEXT: store i32 [[ZEXT_67]], i32* @G, align 4
; CHECK-NEXT: [[CMP_68:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_68:%.*]] = sext i1 [[CMP_68]] to i32
; CHECK-NEXT: store i32 [[ZEXT_68]], i32* @G, align 4
; CHECK-NEXT: [[CMP_69:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_69:%.*]] = sext i1 [[CMP_69]] to i32
; CHECK-NEXT: store i32 [[ZEXT_69]], i32* @G, align 4
; CHECK-NEXT: [[CMP_70:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_70:%.*]] = sext i1 [[CMP_70]] to i32
; CHECK-NEXT: store i32 [[ZEXT_70]], i32* @G, align 4
; CHECK-NEXT: [[CMP_71:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_71:%.*]] = sext i1 [[CMP_71]] to i32
; CHECK-NEXT: store i32 [[ZEXT_71]], i32* @G, align 4
; CHECK-NEXT: [[CMP_72:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_72:%.*]] = sext i1 [[CMP_72]] to i32
; CHECK-NEXT: store i32 [[ZEXT_72]], i32* @G, align 4
; CHECK-NEXT: [[CMP_73:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_73:%.*]] = sext i1 [[CMP_73]] to i32
; CHECK-NEXT: store i32 [[ZEXT_73]], i32* @G, align 4
; CHECK-NEXT: [[CMP_74:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_74:%.*]] = sext i1 [[CMP_74]] to i32
; CHECK-NEXT: store i32 [[ZEXT_74]], i32* @G, align 4
; CHECK-NEXT: [[CMP_75:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_75:%.*]] = sext i1 [[CMP_75]] to i32
; CHECK-NEXT: store i32 [[ZEXT_75]], i32* @G, align 4
; CHECK-NEXT: [[CMP_76:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_76:%.*]] = sext i1 [[CMP_76]] to i32
; CHECK-NEXT: store i32 [[ZEXT_76]], i32* @G, align 4
; CHECK-NEXT: [[CMP_77:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_77:%.*]] = sext i1 [[CMP_77]] to i32
; CHECK-NEXT: store i32 [[ZEXT_77]], i32* @G, align 4
; CHECK-NEXT: [[CMP_78:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_78:%.*]] = sext i1 [[CMP_78]] to i32
; CHECK-NEXT: store i32 [[ZEXT_78]], i32* @G, align 4
; CHECK-NEXT: [[CMP_79:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_79:%.*]] = sext i1 [[CMP_79]] to i32
; CHECK-NEXT: store i32 [[ZEXT_79]], i32* @G, align 4
; CHECK-NEXT: [[CMP_80:%.*]] = icmp eq i32 0, [[LIMIT]]
; CHECK-NEXT: [[ZEXT_80:%.*]] = sext i1 [[CMP_80]] to i32
; CHECK-NEXT: store i32 [[ZEXT_80]], i32* @G, align 4
; CHECK-NEXT: ret i32 [[ZEXT_80]]
;
entry:
br label %loop
@ -69,11 +282,7 @@ define i32 @test_symbolic_path(i32 %limit) {
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[SUM:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[SUM_NEXT:%.*]], [[BACKEDGE:%.*]] ]
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IV_NEXT:%.*]], [[BACKEDGE]] ]
; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[LIMIT:%.*]], [[SUM]]
; CHECK-NEXT: [[IS_POSITIVE:%.*]] = icmp eq i32 [[SUB]], [[LIMIT]]
; CHECK-NEXT: br i1 [[IS_POSITIVE]], label [[BACKEDGE]], label [[IF_FALSE:%.*]]
; CHECK-NEXT: br i1 true, label [[BACKEDGE:%.*]], label [[IF_FALSE:%.*]]
; CHECK: if.false:
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
@ -91,14 +300,151 @@ define i32 @test_symbolic_path(i32 %limit) {
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: br label [[BACKEDGE]]
; CHECK: backedge:
; CHECK-NEXT: [[HIDDEN_ZERO:%.*]] = sub i32 [[LIMIT]], [[SUB]]
; CHECK-NEXT: [[SUM_NEXT]] = add i32 [[SUM]], [[HIDDEN_ZERO]]
; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
; CHECK-NEXT: [[LOOP_COND:%.*]] = icmp ne i32 [[IV]], 8
; CHECK-NEXT: br i1 [[LOOP_COND]], label [[LOOP]], label [[DONE:%.*]]
; CHECK: done:
; CHECK-NEXT: [[SUM_NEXT_LCSSA:%.*]] = phi i32 [ [[SUM_NEXT]], [[BACKEDGE]] ]
; CHECK-NEXT: ret i32 [[SUM_NEXT_LCSSA]]
; CHECK-NEXT: br i1 true, label [[BACKEDGE_1:%.*]], label [[IF_FALSE_1:%.*]]
; CHECK: if.false.1:
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: br label [[BACKEDGE_1]]
; CHECK: backedge.1:
; CHECK-NEXT: br i1 true, label [[BACKEDGE_2:%.*]], label [[IF_FALSE_2:%.*]]
; CHECK: if.false.2:
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: br label [[BACKEDGE_2]]
; CHECK: backedge.2:
; CHECK-NEXT: br i1 true, label [[BACKEDGE_3:%.*]], label [[IF_FALSE_3:%.*]]
; CHECK: if.false.3:
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: br label [[BACKEDGE_3]]
; CHECK: backedge.3:
; CHECK-NEXT: br i1 true, label [[BACKEDGE_4:%.*]], label [[IF_FALSE_4:%.*]]
; CHECK: if.false.4:
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: br label [[BACKEDGE_4]]
; CHECK: backedge.4:
; CHECK-NEXT: br i1 true, label [[BACKEDGE_5:%.*]], label [[IF_FALSE_5:%.*]]
; CHECK: if.false.5:
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: br label [[BACKEDGE_5]]
; CHECK: backedge.5:
; CHECK-NEXT: br i1 true, label [[BACKEDGE_6:%.*]], label [[IF_FALSE_6:%.*]]
; CHECK: if.false.6:
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: br label [[BACKEDGE_6]]
; CHECK: backedge.6:
; CHECK-NEXT: br i1 true, label [[BACKEDGE_7:%.*]], label [[IF_FALSE_7:%.*]]
; CHECK: if.false.7:
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: br label [[BACKEDGE_7]]
; CHECK: backedge.7:
; CHECK-NEXT: br i1 true, label [[BACKEDGE_8:%.*]], label [[IF_FALSE_8:%.*]]
; CHECK: if.false.8:
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: br label [[BACKEDGE_8]]
; CHECK: backedge.8:
; CHECK-NEXT: ret i32 0
;
entry:
br label %loop

View File

@ -19,7 +19,7 @@ using namespace llvm;
namespace llvm {
void initializeUnrollAnalyzerTestPass(PassRegistry &);
static SmallVector<DenseMap<Value *, Constant *>, 16> SimplifiedValuesVector;
static SmallVector<DenseMap<Value *, Value *>, 16> SimplifiedValuesVector;
static unsigned TripCount = 0;
namespace {
@ -38,7 +38,7 @@ struct UnrollAnalyzerTest : public FunctionPass {
SimplifiedValuesVector.clear();
TripCount = SE->getSmallConstantTripCount(L, Exiting);
for (unsigned Iteration = 0; Iteration < TripCount; Iteration++) {
DenseMap<Value *, Constant *> SimplifiedValues;
DenseMap<Value *, Value *> SimplifiedValues;
UnrolledInstAnalyzer Analyzer(Iteration, SimplifiedValues, *SE, L);
for (auto *BB : L->getBlocks())
for (Instruction &I : *BB)