1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-26 12:43:36 +01:00

[VPlan] Use consecutive numbers to print VPValues instead of addresses.

Currently when printing VPValues we use the object address, which makes
it hard to distinguish VPValues as they usually are large numbers with
varying distance between them.

This patch adds a simple slot tracker, similar to the ModuleSlotTracker
used for IR values. In order to dump a VPValue or anything containing a
VPValue, a slot tracker for the enclosing VPlan needs to be created. The
existing VPlanPrinter can take care of that for the existing code. We
assign consecutive numbers to each VPValue we encounter in a reverse
post order traversal of the VPlan.

Reviewers: rengolin, hsaito, fhahn, Ayal, dorit, gilr

Reviewed By: gilr

Differential Revision: https://reviews.llvm.org/D73078
This commit is contained in:
Florian Hahn 2020-03-05 14:55:08 +00:00
parent 77f345b07b
commit 45b8bf3b33
5 changed files with 253 additions and 50 deletions

View File

@ -7347,16 +7347,17 @@ Value *LoopVectorizationPlanner::VPCallbackILV::getOrCreateScalarValue(
return ILV.getOrCreateScalarValue(V, Instance); return ILV.getOrCreateScalarValue(V, Instance);
} }
void VPInterleaveRecipe::print(raw_ostream &O, const Twine &Indent) const { void VPInterleaveRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << " +\n" O << " +\n"
<< Indent << "\"INTERLEAVE-GROUP with factor " << IG->getFactor() << " at "; << Indent << "\"INTERLEAVE-GROUP with factor " << IG->getFactor() << " at ";
IG->getInsertPos()->printAsOperand(O, false); IG->getInsertPos()->printAsOperand(O, false);
O << ", "; O << ", ";
getAddr()->printAsOperand(O); getAddr()->printAsOperand(O, SlotTracker);
VPValue *Mask = getMask(); VPValue *Mask = getMask();
if (Mask) { if (Mask) {
O << ", "; O << ", ";
Mask->printAsOperand(O); Mask->printAsOperand(O, SlotTracker);
} }
O << "\\l\""; O << "\\l\"";
for (unsigned i = 0; i < IG->getFactor(); ++i) for (unsigned i = 0; i < IG->getFactor(); ++i)

View File

@ -49,13 +49,20 @@ extern cl::opt<bool> EnableVPlanNativePath;
#define DEBUG_TYPE "vplan" #define DEBUG_TYPE "vplan"
raw_ostream &llvm::operator<<(raw_ostream &OS, const VPValue &V) { raw_ostream &llvm::operator<<(raw_ostream &OS, const VPValue &V) {
if (const VPInstruction *Instr = dyn_cast<VPInstruction>(&V)) const VPInstruction *Instr = dyn_cast<VPInstruction>(&V);
Instr->print(OS); VPSlotTracker SlotTracker(
else (Instr && Instr->getParent()) ? Instr->getParent()->getPlan() : nullptr);
V.printAsOperand(OS); V.print(OS, SlotTracker);
return OS; return OS;
} }
void VPValue::print(raw_ostream &OS, VPSlotTracker &SlotTracker) const {
if (const VPInstruction *Instr = dyn_cast<VPInstruction>(this))
Instr->print(OS, SlotTracker);
else
printAsOperand(OS, SlotTracker);
}
// Get the top-most entry block of \p Start. This is the entry block of the // Get the top-most entry block of \p Start. This is the entry block of the
// containing VPlan. This function is templated to support both const and non-const blocks // containing VPlan. This function is templated to support both const and non-const blocks
template <typename T> static T *getPlanEntry(T *Start) { template <typename T> static T *getPlanEntry(T *Start) {
@ -384,14 +391,20 @@ void VPInstruction::execute(VPTransformState &State) {
generateInstruction(State, Part); generateInstruction(State, Part);
} }
void VPInstruction::print(raw_ostream &O, const Twine &Indent) const { void VPInstruction::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << " +\n" << Indent << "\"EMIT "; O << " +\n" << Indent << "\"EMIT ";
print(O); print(O, SlotTracker);
O << "\\l\""; O << "\\l\"";
} }
void VPInstruction::print(raw_ostream &O) const { void VPInstruction::print(raw_ostream &O) const {
printAsOperand(O); VPSlotTracker SlotTracker(getParent()->getPlan());
print(O, SlotTracker);
}
void VPInstruction::print(raw_ostream &O, VPSlotTracker &SlotTracker) const {
printAsOperand(O, SlotTracker);
O << " = "; O << " = ";
switch (getOpcode()) { switch (getOpcode()) {
@ -413,7 +426,7 @@ void VPInstruction::print(raw_ostream &O) const {
for (const VPValue *Operand : operands()) { for (const VPValue *Operand : operands()) {
O << " "; O << " ";
Operand->printAsOperand(O); Operand->printAsOperand(O, SlotTracker);
} }
} }
@ -567,10 +580,14 @@ void VPlanPrinter::dump() {
OS << "\\n" << DOT::EscapeString(Plan.getName()); OS << "\\n" << DOT::EscapeString(Plan.getName());
if (!Plan.Value2VPValue.empty() || Plan.BackedgeTakenCount) { if (!Plan.Value2VPValue.empty() || Plan.BackedgeTakenCount) {
OS << ", where:"; OS << ", where:";
if (Plan.BackedgeTakenCount) if (Plan.BackedgeTakenCount) {
OS << "\\n" << *Plan.BackedgeTakenCount << " := BackedgeTakenCount"; OS << "\\n";
Plan.BackedgeTakenCount->print(OS, SlotTracker);
OS << " := BackedgeTakenCount";
}
for (auto Entry : Plan.Value2VPValue) { for (auto Entry : Plan.Value2VPValue) {
OS << "\\n" << *Entry.second; OS << "\\n";
Entry.second->print(OS, SlotTracker);
OS << DOT::EscapeString(" := "); OS << DOT::EscapeString(" := ");
Entry.first->printAsOperand(OS, false); Entry.first->printAsOperand(OS, false);
} }
@ -637,25 +654,25 @@ void VPlanPrinter::dumpBasicBlock(const VPBasicBlock *BasicBlock) {
if (Pred) { if (Pred) {
OS << " +\n" << Indent << " \"BlockPredicate: "; OS << " +\n" << Indent << " \"BlockPredicate: ";
if (const VPInstruction *PredI = dyn_cast<VPInstruction>(Pred)) { if (const VPInstruction *PredI = dyn_cast<VPInstruction>(Pred)) {
PredI->printAsOperand(OS); PredI->printAsOperand(OS, SlotTracker);
OS << " (" << DOT::EscapeString(PredI->getParent()->getName()) OS << " (" << DOT::EscapeString(PredI->getParent()->getName())
<< ")\\l\""; << ")\\l\"";
} else } else
Pred->printAsOperand(OS); Pred->printAsOperand(OS, SlotTracker);
} }
for (const VPRecipeBase &Recipe : *BasicBlock) for (const VPRecipeBase &Recipe : *BasicBlock)
Recipe.print(OS, Indent); Recipe.print(OS, Indent, SlotTracker);
// Dump the condition bit. // Dump the condition bit.
const VPValue *CBV = BasicBlock->getCondBit(); const VPValue *CBV = BasicBlock->getCondBit();
if (CBV) { if (CBV) {
OS << " +\n" << Indent << " \"CondBit: "; OS << " +\n" << Indent << " \"CondBit: ";
if (const VPInstruction *CBI = dyn_cast<VPInstruction>(CBV)) { if (const VPInstruction *CBI = dyn_cast<VPInstruction>(CBV)) {
CBI->printAsOperand(OS); CBI->printAsOperand(OS, SlotTracker);
OS << " (" << DOT::EscapeString(CBI->getParent()->getName()) << ")\\l\""; OS << " (" << DOT::EscapeString(CBI->getParent()->getName()) << ")\\l\"";
} else { } else {
CBV->printAsOperand(OS); CBV->printAsOperand(OS, SlotTracker);
OS << "\""; OS << "\"";
} }
} }
@ -702,14 +719,15 @@ void VPlanPrinter::printAsIngredient(raw_ostream &O, Value *V) {
O << DOT::EscapeString(IngredientString); O << DOT::EscapeString(IngredientString);
} }
void VPWidenRecipe::print(raw_ostream &O, const Twine &Indent) const { void VPWidenRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << " +\n" << Indent << "\"WIDEN\\l\""; O << " +\n" << Indent << "\"WIDEN\\l\"";
for (auto &Instr : make_range(Begin, End)) for (auto &Instr : make_range(Begin, End))
O << " +\n" << Indent << "\" " << VPlanIngredient(&Instr) << "\\l\""; O << " +\n" << Indent << "\" " << VPlanIngredient(&Instr) << "\\l\"";
} }
void VPWidenIntOrFpInductionRecipe::print(raw_ostream &O, void VPWidenIntOrFpInductionRecipe::print(raw_ostream &O, const Twine &Indent,
const Twine &Indent) const { VPSlotTracker &SlotTracker) const {
O << " +\n" << Indent << "\"WIDEN-INDUCTION"; O << " +\n" << Indent << "\"WIDEN-INDUCTION";
if (Trunc) { if (Trunc) {
O << "\\l\""; O << "\\l\"";
@ -719,7 +737,8 @@ void VPWidenIntOrFpInductionRecipe::print(raw_ostream &O,
O << " " << VPlanIngredient(IV) << "\\l\""; O << " " << VPlanIngredient(IV) << "\\l\"";
} }
void VPWidenGEPRecipe::print(raw_ostream &O, const Twine &Indent) const { void VPWidenGEPRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << " +\n" << Indent << "\"WIDEN-GEP "; O << " +\n" << Indent << "\"WIDEN-GEP ";
O << (IsPtrLoopInvariant ? "Inv" : "Var"); O << (IsPtrLoopInvariant ? "Inv" : "Var");
size_t IndicesNumber = IsIndexLoopInvariant.size(); size_t IndicesNumber = IsIndexLoopInvariant.size();
@ -729,11 +748,13 @@ void VPWidenGEPRecipe::print(raw_ostream &O, const Twine &Indent) const {
O << " +\n" << Indent << "\" " << VPlanIngredient(GEP) << "\\l\""; O << " +\n" << Indent << "\" " << VPlanIngredient(GEP) << "\\l\"";
} }
void VPWidenPHIRecipe::print(raw_ostream &O, const Twine &Indent) const { void VPWidenPHIRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << " +\n" << Indent << "\"WIDEN-PHI " << VPlanIngredient(Phi) << "\\l\""; O << " +\n" << Indent << "\"WIDEN-PHI " << VPlanIngredient(Phi) << "\\l\"";
} }
void VPBlendRecipe::print(raw_ostream &O, const Twine &Indent) const { void VPBlendRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << " +\n" << Indent << "\"BLEND "; O << " +\n" << Indent << "\"BLEND ";
Phi->printAsOperand(O, false); Phi->printAsOperand(O, false);
O << " ="; O << " =";
@ -747,13 +768,14 @@ void VPBlendRecipe::print(raw_ostream &O, const Twine &Indent) const {
O << " "; O << " ";
Phi->getIncomingValue(I)->printAsOperand(O, false); Phi->getIncomingValue(I)->printAsOperand(O, false);
O << "/"; O << "/";
User->getOperand(I)->printAsOperand(O); User->getOperand(I)->printAsOperand(O, SlotTracker);
} }
} }
O << "\\l\""; O << "\\l\"";
} }
void VPReplicateRecipe::print(raw_ostream &O, const Twine &Indent) const { void VPReplicateRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << " +\n" O << " +\n"
<< Indent << "\"" << (IsUniform ? "CLONE " : "REPLICATE ") << Indent << "\"" << (IsUniform ? "CLONE " : "REPLICATE ")
<< VPlanIngredient(Ingredient); << VPlanIngredient(Ingredient);
@ -762,21 +784,22 @@ void VPReplicateRecipe::print(raw_ostream &O, const Twine &Indent) const {
O << "\\l\""; O << "\\l\"";
} }
void VPPredInstPHIRecipe::print(raw_ostream &O, const Twine &Indent) const { void VPPredInstPHIRecipe::print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const {
O << " +\n" O << " +\n"
<< Indent << "\"PHI-PREDICATED-INSTRUCTION " << VPlanIngredient(PredInst) << Indent << "\"PHI-PREDICATED-INSTRUCTION " << VPlanIngredient(PredInst)
<< "\\l\""; << "\\l\"";
} }
void VPWidenMemoryInstructionRecipe::print(raw_ostream &O, void VPWidenMemoryInstructionRecipe::print(raw_ostream &O, const Twine &Indent,
const Twine &Indent) const { VPSlotTracker &SlotTracker) const {
O << " +\n" << Indent << "\"WIDEN " << VPlanIngredient(&Instr); O << " +\n" << Indent << "\"WIDEN " << VPlanIngredient(&Instr);
O << ", "; O << ", ";
getAddr()->printAsOperand(O); getAddr()->printAsOperand(O, SlotTracker);
VPValue *Mask = getMask(); VPValue *Mask = getMask();
if (Mask) { if (Mask) {
O << ", "; O << ", ";
Mask->printAsOperand(O); Mask->printAsOperand(O, SlotTracker);
} }
O << "\\l\""; O << "\\l\"";
} }
@ -790,6 +813,14 @@ void VPValue::replaceAllUsesWith(VPValue *New) {
User->setOperand(I, New); User->setOperand(I, New);
} }
void VPValue::printAsOperand(raw_ostream &OS, VPSlotTracker &Tracker) const {
unsigned Slot = Tracker.getSlot(this);
if (Slot == unsigned(-1))
OS << "<badref>";
else
OS << "%vp" << Tracker.getSlot(this);
}
void VPInterleavedAccessInfo::visitRegion(VPRegionBlock *Region, void VPInterleavedAccessInfo::visitRegion(VPRegionBlock *Region,
Old2NewTy &Old2New, Old2NewTy &Old2New,
InterleavedAccessInfo &IAI) { InterleavedAccessInfo &IAI) {
@ -835,3 +866,48 @@ VPInterleavedAccessInfo::VPInterleavedAccessInfo(VPlan &Plan,
Old2NewTy Old2New; Old2NewTy Old2New;
visitRegion(cast<VPRegionBlock>(Plan.getEntry()), Old2New, IAI); visitRegion(cast<VPRegionBlock>(Plan.getEntry()), Old2New, IAI);
} }
void VPSlotTracker::assignSlot(const VPValue *V) {
assert(Slots.find(V) == Slots.end() && "VPValue already has a slot!");
Slots[V] = NextSlot++;
}
void VPSlotTracker::assignSlots(const VPBlockBase *VPBB) {
if (auto *Region = dyn_cast<VPRegionBlock>(VPBB))
assignSlots(Region);
else
assignSlots(cast<VPBasicBlock>(VPBB));
}
void VPSlotTracker::assignSlots(const VPRegionBlock *Region) {
ReversePostOrderTraversal<const VPBlockBase *> RPOT(Region->getEntry());
for (const VPBlockBase *Block : RPOT)
assignSlots(Block);
}
void VPSlotTracker::assignSlots(const VPBasicBlock *VPBB) {
for (const VPRecipeBase &Recipe : *VPBB) {
if (const auto *VPI = dyn_cast<VPInstruction>(&Recipe))
assignSlot(VPI);
}
}
void VPSlotTracker::assignSlots(const VPlan &Plan) {
for (const VPValue *V : Plan.VPExternalDefs)
assignSlot(V);
for (auto &E : Plan.Value2VPValue)
if (!isa<VPInstruction>(E.second))
assignSlot(E.second);
for (const VPValue *V : Plan.VPCBVs)
assignSlot(V);
if (Plan.BackedgeTakenCount)
assignSlot(Plan.BackedgeTakenCount);
ReversePostOrderTraversal<const VPBlockBase *> RPOT(Plan.getEntry());
for (const VPBlockBase *Block : RPOT)
assignSlots(Block);
}

View File

@ -633,7 +633,9 @@ public:
virtual void execute(struct VPTransformState &State) = 0; virtual void execute(struct VPTransformState &State) = 0;
/// Each recipe prints itself. /// Each recipe prints itself.
virtual void print(raw_ostream &O, const Twine &Indent) const = 0; void print(raw_ostream &O, const Twine &Indent);
virtual void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const = 0;
/// Insert an unlinked recipe into a basic block immediately before /// Insert an unlinked recipe into a basic block immediately before
/// the specified recipe. /// the specified recipe.
@ -719,10 +721,12 @@ public:
void execute(VPTransformState &State) override; void execute(VPTransformState &State) override;
/// Print the Recipe. /// Print the Recipe.
void print(raw_ostream &O, const Twine &Indent) const override; void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
/// Print the VPInstruction. /// Print the VPInstruction.
void print(raw_ostream &O) const; void print(raw_ostream &O) const;
void print(raw_ostream &O, VPSlotTracker &SlotTracker) const;
/// Return true if this instruction may modify memory. /// Return true if this instruction may modify memory.
bool mayWriteToMemory() const { bool mayWriteToMemory() const {
@ -768,7 +772,8 @@ public:
} }
/// Print the recipe. /// Print the recipe.
void print(raw_ostream &O, const Twine &Indent) const override; void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
}; };
/// A recipe for handling GEP instructions. /// A recipe for handling GEP instructions.
@ -798,7 +803,8 @@ public:
void execute(VPTransformState &State) override; void execute(VPTransformState &State) override;
/// Print the recipe. /// Print the recipe.
void print(raw_ostream &O, const Twine &Indent) const override; void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
}; };
/// A recipe for handling phi nodes of integer and floating-point inductions, /// A recipe for handling phi nodes of integer and floating-point inductions,
@ -823,7 +829,8 @@ public:
void execute(VPTransformState &State) override; void execute(VPTransformState &State) override;
/// Print the recipe. /// Print the recipe.
void print(raw_ostream &O, const Twine &Indent) const override; void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
}; };
/// A recipe for handling all phi nodes except for integer and FP inductions. /// A recipe for handling all phi nodes except for integer and FP inductions.
@ -844,7 +851,8 @@ public:
void execute(VPTransformState &State) override; void execute(VPTransformState &State) override;
/// Print the recipe. /// Print the recipe.
void print(raw_ostream &O, const Twine &Indent) const override; void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
}; };
/// A recipe for vectorizing a phi-node as a sequence of mask-based select /// A recipe for vectorizing a phi-node as a sequence of mask-based select
@ -875,7 +883,8 @@ public:
void execute(VPTransformState &State) override; void execute(VPTransformState &State) override;
/// Print the recipe. /// Print the recipe.
void print(raw_ostream &O, const Twine &Indent) const override; void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
}; };
/// VPInterleaveRecipe is a recipe for transforming an interleave group of load /// VPInterleaveRecipe is a recipe for transforming an interleave group of load
@ -915,7 +924,8 @@ public:
void execute(VPTransformState &State) override; void execute(VPTransformState &State) override;
/// Print the recipe. /// Print the recipe.
void print(raw_ostream &O, const Twine &Indent) const override; void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
const InterleaveGroup<Instruction> *getInterleaveGroup() { return IG; } const InterleaveGroup<Instruction> *getInterleaveGroup() { return IG; }
}; };
@ -965,7 +975,8 @@ public:
void setAlsoPack(bool Pack) { AlsoPack = Pack; } void setAlsoPack(bool Pack) { AlsoPack = Pack; }
/// Print the recipe. /// Print the recipe.
void print(raw_ostream &O, const Twine &Indent) const override; void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
}; };
/// A recipe for generating conditional branches on the bits of a mask. /// A recipe for generating conditional branches on the bits of a mask.
@ -989,10 +1000,11 @@ public:
void execute(VPTransformState &State) override; void execute(VPTransformState &State) override;
/// Print the recipe. /// Print the recipe.
void print(raw_ostream &O, const Twine &Indent) const override { void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override {
O << " +\n" << Indent << "\"BRANCH-ON-MASK "; O << " +\n" << Indent << "\"BRANCH-ON-MASK ";
if (User) if (User)
O << *User->getOperand(0); User->getOperand(0)->print(O, SlotTracker);
else else
O << " All-One"; O << " All-One";
O << "\\l\""; O << "\\l\"";
@ -1024,7 +1036,8 @@ public:
void execute(VPTransformState &State) override; void execute(VPTransformState &State) override;
/// Print the recipe. /// Print the recipe.
void print(raw_ostream &O, const Twine &Indent) const override; void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
}; };
/// A Recipe for widening load/store operations. /// A Recipe for widening load/store operations.
@ -1064,7 +1077,8 @@ public:
void execute(VPTransformState &State) override; void execute(VPTransformState &State) override;
/// Print the recipe. /// Print the recipe.
void print(raw_ostream &O, const Twine &Indent) const override; void print(raw_ostream &O, const Twine &Indent,
VPSlotTracker &SlotTracker) const override;
}; };
/// VPBasicBlock serves as the leaf of the Hierarchical Control-Flow Graph. It /// VPBasicBlock serves as the leaf of the Hierarchical Control-Flow Graph. It
@ -1352,6 +1366,7 @@ struct GraphTraits<Inverse<VPRegionBlock *>>
} }
}; };
class VPSlotTracker;
/// VPlan models a candidate for vectorization, encoding various decisions take /// VPlan models a candidate for vectorization, encoding various decisions take
/// to produce efficient output IR, including which branches, basic-blocks and /// to produce efficient output IR, including which branches, basic-blocks and
/// output IR instructions to generate, and their cost. VPlan holds a /// output IR instructions to generate, and their cost. VPlan holds a
@ -1359,6 +1374,7 @@ struct GraphTraits<Inverse<VPRegionBlock *>>
/// VPBlock. /// VPBlock.
class VPlan { class VPlan {
friend class VPlanPrinter; friend class VPlanPrinter;
friend class VPSlotTracker;
private: private:
/// Hold the single entry to the Hierarchical CFG of the VPlan. /// Hold the single entry to the Hierarchical CFG of the VPlan.
@ -1392,7 +1408,10 @@ private:
SmallVector<VPValue *, 4> VPCBVs; SmallVector<VPValue *, 4> VPCBVs;
public: public:
VPlan(VPBlockBase *Entry = nullptr) : Entry(Entry) {} VPlan(VPBlockBase *Entry = nullptr) : Entry(Entry) {
if (Entry)
Entry->setPlan(this);
}
~VPlan() { ~VPlan() {
if (Entry) if (Entry)
@ -1496,7 +1515,10 @@ private:
unsigned BID = 0; unsigned BID = 0;
SmallDenseMap<const VPBlockBase *, unsigned> BlockID; SmallDenseMap<const VPBlockBase *, unsigned> BlockID;
VPlanPrinter(raw_ostream &O, const VPlan &P) : OS(O), Plan(P) {} VPSlotTracker SlotTracker;
VPlanPrinter(raw_ostream &O, const VPlan &P)
: OS(O), Plan(P), SlotTracker(&P) {}
/// Handle indentation. /// Handle indentation.
void bumpIndent(int b) { Indent = std::string((Depth += b) * TabWidth, ' '); } void bumpIndent(int b) { Indent = std::string((Depth += b) * TabWidth, ' '); }

View File

@ -31,6 +31,8 @@ namespace llvm {
// Forward declarations. // Forward declarations.
class VPUser; class VPUser;
class VPSlotTracker;
// This is the base class of the VPlan Def/Use graph, used for modeling the data // This is the base class of the VPlan Def/Use graph, used for modeling the data
// flow into, within and out of the VPlan. VPValues can stand for live-ins // flow into, within and out of the VPlan. VPValues can stand for live-ins
// coming from the input IR, instructions which VPlan will generate if executed // coming from the input IR, instructions which VPlan will generate if executed
@ -85,9 +87,8 @@ public:
/// for any other purpose, as the values may change as LLVM evolves. /// for any other purpose, as the values may change as LLVM evolves.
unsigned getVPValueID() const { return SubclassID; } unsigned getVPValueID() const { return SubclassID; }
void printAsOperand(raw_ostream &OS) const { void printAsOperand(raw_ostream &OS, VPSlotTracker &Tracker) const;
OS << "%vp" << (unsigned short)(unsigned long long)this; void print(raw_ostream &OS, VPSlotTracker &Tracker) const;
}
unsigned getNumUsers() const { return Users.size(); } unsigned getNumUsers() const { return Users.size(); }
void addUser(VPUser &User) { Users.push_back(&User); } void addUser(VPUser &User) { Users.push_back(&User); }
@ -180,6 +181,38 @@ public:
return const_operand_range(op_begin(), op_end()); return const_operand_range(op_begin(), op_end());
} }
}; };
class VPlan;
class VPBasicBlock;
class VPRegionBlock;
/// This class can be used to assign consecutive numbers to all VPValues in a
/// VPlan and allows querying the numbering for printing, similar to the
/// ModuleSlotTracker for IR values.
class VPSlotTracker {
private:
DenseMap<const VPValue *, unsigned> Slots;
unsigned NextSlot = 0;
void assignSlots(const VPBlockBase *VPBB);
void assignSlots(const VPRegionBlock *Region);
void assignSlots(const VPBasicBlock *VPBB);
void assignSlot(const VPValue *V);
void assignSlots(const VPlan &Plan);
public:
VPSlotTracker(const VPlan *Plan) {
if (Plan)
assignSlots(*Plan);
}
unsigned getSlot(const VPValue *V) const {
auto I = Slots.find(V);
if (I == Slots.end())
return -1;
return I->second;
}
};
} // namespace llvm } // namespace llvm

View File

@ -11,6 +11,7 @@
#include "llvm/IR/Instruction.h" #include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h" #include "llvm/IR/Instructions.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include <string>
namespace llvm { namespace llvm {
namespace { namespace {
@ -176,5 +177,75 @@ TEST(VPBasicBlockTest, getPlan) {
} }
} }
TEST(VPBasicBlockTest, print) {
VPInstruction *I1 = new VPInstruction(10, {});
VPInstruction *I2 = new VPInstruction(1, {I1});
VPInstruction *I3 = new VPInstruction(2, {I1, I2});
VPBasicBlock *VPBB1 = new VPBasicBlock();
VPBB1->appendRecipe(I1);
VPBB1->appendRecipe(I2);
VPBB1->appendRecipe(I3);
VPInstruction *I4 = new VPInstruction(4, {I3, I2});
VPInstruction *I5 = new VPInstruction(5, {I1});
VPBasicBlock *VPBB2 = new VPBasicBlock();
VPBB2->appendRecipe(I4);
VPBB2->appendRecipe(I5);
VPBlockUtils::connectBlocks(VPBB1, VPBB2);
// Check printing an instruction without associated VPlan.
{
std::string I3Dump;
raw_string_ostream OS(I3Dump);
I3->print(OS);
OS.flush();
EXPECT_EQ("<badref> = br <badref> <badref>", I3Dump);
}
VPlan Plan;
Plan.setEntry(VPBB1);
std::string FullDump;
raw_string_ostream(FullDump) << Plan;
EXPECT_EQ(R"(digraph VPlan {
graph [labelloc=t, fontsize=30; label="Vectorization Plan"]
node [shape=rect, fontname=Courier, fontsize=30]
edge [fontname=Courier, fontsize=30]
compound=true
N0 [label =
":\n" +
"EMIT %vp0 = catchswitch\l" +
"EMIT %vp1 = ret %vp0\l" +
"EMIT %vp2 = br %vp0 %vp1\l"
]
N0 -> N1 [ label=""]
N1 [label =
":\n" +
"EMIT %vp3 = indirectbr %vp2 %vp1\l" +
"EMIT %vp4 = invoke %vp0\l"
]
}
)",
FullDump);
{
std::string I3Dump;
raw_string_ostream OS(I3Dump);
I3->print(OS);
OS.flush();
EXPECT_EQ("%vp2 = br %vp0 %vp1", I3Dump);
}
{
std::string I2Dump;
raw_string_ostream OS(I2Dump);
OS << *I2;
OS.flush();
EXPECT_EQ("%vp1 = ret %vp0", I2Dump);
}
}
} // namespace } // namespace
} // namespace llvm } // namespace llvm