diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp --- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -7358,15 +7358,21 @@ } void VPInterleaveRecipe::print(raw_ostream &O, const Twine &Indent) const { + VPSlotTracker SlotTracker; + print(O, Indent, SlotTracker); +} + +void VPInterleaveRecipe::print(raw_ostream &O, const Twine &Indent, + VPSlotTracker &SlotTracker) const { O << " +\n" << Indent << "\"INTERLEAVE-GROUP with factor " << IG->getFactor() << " at "; IG->getInsertPos()->printAsOperand(O, false); O << ", "; - getAddr()->printAsOperand(O); + getAddr()->printAsOperand(O, SlotTracker); VPValue *Mask = getMask(); if (Mask) { O << ", "; - Mask->printAsOperand(O); + Mask->printAsOperand(O, SlotTracker); } O << "\\l\""; for (unsigned i = 0; i < IG->getFactor(); ++i) diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h --- a/llvm/lib/Transforms/Vectorize/VPlan.h +++ b/llvm/lib/Transforms/Vectorize/VPlan.h @@ -627,6 +627,8 @@ /// Each recipe prints itself. virtual void print(raw_ostream &O, const Twine &Indent) const = 0; + virtual void print(raw_ostream &O, const Twine &Indent, + VPSlotTracker &SlotTracker) const = 0; /// Insert an unlinked recipe into a basic block immediately before /// the specified recipe. @@ -713,9 +715,12 @@ /// 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. void print(raw_ostream &O) const; + void print(raw_ostream &O, VPSlotTracker &SlotTracker) const; /// Return true if this instruction may modify memory. bool mayWriteToMemory() const { @@ -762,6 +767,8 @@ /// 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. @@ -792,6 +799,8 @@ /// 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, @@ -817,6 +826,8 @@ /// 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. @@ -838,6 +849,8 @@ /// 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 @@ -869,6 +882,8 @@ /// 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 @@ -909,6 +924,8 @@ /// 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 *getInterleaveGroup() { return IG; } }; @@ -959,6 +976,8 @@ /// 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. @@ -983,9 +1002,15 @@ /// Print the recipe. void print(raw_ostream &O, const Twine &Indent) const override { + VPSlotTracker SlotTracker; + print(O, Indent, SlotTracker); + } + + void print(raw_ostream &O, const Twine &Indent, + VPSlotTracker &SlotTracker) const override { O << " +\n" << Indent << "\"BRANCH-ON-MASK "; if (User) - O << *User->getOperand(0); + User->getOperand(0)->print(O, SlotTracker); else O << " All-One"; O << "\\l\""; @@ -1018,6 +1043,9 @@ /// 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. @@ -1058,6 +1086,8 @@ /// 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 @@ -1347,6 +1377,7 @@ } }; +class VPSlotTracker; /// VPlan models a candidate for vectorization, encoding various decisions take /// to produce efficient output IR, including which branches, basic-blocks and /// output IR instructions to generate, and their cost. VPlan holds a @@ -1354,6 +1385,7 @@ /// VPBlock. class VPlan { friend class VPlanPrinter; + friend class VPSlotTracker; private: /// Hold the single entry to the Hierarchical CFG of the VPlan. @@ -1487,6 +1519,8 @@ unsigned BID = 0; SmallDenseMap BlockID; + VPSlotTracker SlotTracker; + VPlanPrinter(raw_ostream &O, const VPlan &P) : OS(O), Plan(P) {} /// Handle indentation. diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp --- a/llvm/lib/Transforms/Vectorize/VPlan.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp @@ -48,12 +48,11 @@ #define DEBUG_TYPE "vplan" -raw_ostream &llvm::operator<<(raw_ostream &OS, const VPValue &V) { - if (const VPInstruction *Instr = dyn_cast(&V)) - Instr->print(OS); +void VPValue::print(raw_ostream &OS, VPSlotTracker &SlotTracker) const { + if (const VPInstruction *Instr = dyn_cast(this)) + Instr->print(OS, SlotTracker); else - V.printAsOperand(OS); - return OS; + printAsOperand(OS, SlotTracker); } /// \return the VPBasicBlock that is the entry of Block, possibly indirectly. @@ -353,13 +352,24 @@ } void VPInstruction::print(raw_ostream &O, const Twine &Indent) const { + VPSlotTracker SlotTracker; + print(O, Indent, SlotTracker); +} + +void VPInstruction::print(raw_ostream &O, const Twine &Indent, + VPSlotTracker &SlotTracker) const { O << " +\n" << Indent << "\"EMIT "; - print(O); + print(O, SlotTracker); O << "\\l\""; } void VPInstruction::print(raw_ostream &O) const { - printAsOperand(O); + VPSlotTracker SlotTracker; + print(O, SlotTracker); +} + +void VPInstruction::print(raw_ostream &O, VPSlotTracker &SlotTracker) const { + printAsOperand(O, SlotTracker); O << " = "; switch (getOpcode()) { @@ -381,7 +391,7 @@ for (const VPValue *Operand : operands()) { O << " "; - Operand->printAsOperand(O); + Operand->printAsOperand(O, SlotTracker); } } @@ -527,6 +537,7 @@ } void VPlanPrinter::dump() { + SlotTracker.assignSlots(Plan); Depth = 1; bumpIndent(0); OS << "digraph VPlan {\n"; @@ -535,10 +546,14 @@ OS << "\\n" << DOT::EscapeString(Plan.getName()); if (!Plan.Value2VPValue.empty() || Plan.BackedgeTakenCount) { OS << ", where:"; - if (Plan.BackedgeTakenCount) - OS << "\\n" << *Plan.BackedgeTakenCount << " := BackedgeTakenCount"; + if (Plan.BackedgeTakenCount) { + OS << "\\n"; + Plan.BackedgeTakenCount->print(OS, SlotTracker); + OS << " := BackedgeTakenCount"; + } for (auto Entry : Plan.Value2VPValue) { - OS << "\\n" << *Entry.second; + OS << "\\n"; + Entry.second->print(OS, SlotTracker); OS << DOT::EscapeString(" := "); Entry.first->printAsOperand(OS, false); } @@ -605,25 +620,25 @@ if (Pred) { OS << " +\n" << Indent << " \"BlockPredicate: "; if (const VPInstruction *PredI = dyn_cast(Pred)) { - PredI->printAsOperand(OS); + PredI->printAsOperand(OS, SlotTracker); OS << " (" << DOT::EscapeString(PredI->getParent()->getName()) << ")\\l\""; } else - Pred->printAsOperand(OS); + Pred->printAsOperand(OS, SlotTracker); } for (const VPRecipeBase &Recipe : *BasicBlock) - Recipe.print(OS, Indent); + Recipe.print(OS, Indent, SlotTracker); // Dump the condition bit. const VPValue *CBV = BasicBlock->getCondBit(); if (CBV) { OS << " +\n" << Indent << " \"CondBit: "; if (const VPInstruction *CBI = dyn_cast(CBV)) { - CBI->printAsOperand(OS); + CBI->printAsOperand(OS, SlotTracker); OS << " (" << DOT::EscapeString(CBI->getParent()->getName()) << ")\\l\""; } else { - CBV->printAsOperand(OS); + CBV->printAsOperand(OS, SlotTracker); OS << "\""; } } @@ -671,6 +686,12 @@ } void VPWidenRecipe::print(raw_ostream &O, const Twine &Indent) const { + VPSlotTracker SlotTracker; + print(O, Indent, SlotTracker); +} + +void VPWidenRecipe::print(raw_ostream &O, const Twine &Indent, + VPSlotTracker &SlotTracker) const { O << " +\n" << Indent << "\"WIDEN\\l\""; for (auto &Instr : make_range(Begin, End)) O << " +\n" << Indent << "\" " << VPlanIngredient(&Instr) << "\\l\""; @@ -678,6 +699,12 @@ void VPWidenIntOrFpInductionRecipe::print(raw_ostream &O, const Twine &Indent) const { + VPSlotTracker SlotTracker; + print(O, Indent, SlotTracker); +} + +void VPWidenIntOrFpInductionRecipe::print(raw_ostream &O, const Twine &Indent, + VPSlotTracker &SlotTracker) const { O << " +\n" << Indent << "\"WIDEN-INDUCTION"; if (Trunc) { O << "\\l\""; @@ -688,6 +715,12 @@ } void VPWidenGEPRecipe::print(raw_ostream &O, const Twine &Indent) const { + VPSlotTracker SlotTracker; + print(O, Indent, SlotTracker); +} + +void VPWidenGEPRecipe::print(raw_ostream &O, const Twine &Indent, + VPSlotTracker &SlotTracker) const { O << " +\n" << Indent << "\"WIDEN-GEP "; O << (IsPtrLoopInvariant ? "Inv" : "Var"); size_t IndicesNumber = IsIndexLoopInvariant.size(); @@ -698,10 +731,22 @@ } void VPWidenPHIRecipe::print(raw_ostream &O, const Twine &Indent) const { + VPSlotTracker SlotTracker; + print(O, Indent, SlotTracker); +} + +void VPWidenPHIRecipe::print(raw_ostream &O, const Twine &Indent, + VPSlotTracker &SlotTracker) const { O << " +\n" << Indent << "\"WIDEN-PHI " << VPlanIngredient(Phi) << "\\l\""; } void VPBlendRecipe::print(raw_ostream &O, const Twine &Indent) const { + VPSlotTracker SlotTracker; + print(O, Indent, SlotTracker); +} + +void VPBlendRecipe::print(raw_ostream &O, const Twine &Indent, + VPSlotTracker &SlotTracker) const { O << " +\n" << Indent << "\"BLEND "; Phi->printAsOperand(O, false); O << " ="; @@ -715,13 +760,19 @@ O << " "; Phi->getIncomingValue(I)->printAsOperand(O, false); O << "/"; - User->getOperand(I)->printAsOperand(O); + User->getOperand(I)->printAsOperand(O, SlotTracker); } } O << "\\l\""; } void VPReplicateRecipe::print(raw_ostream &O, const Twine &Indent) const { + VPSlotTracker SlotTracker; + print(O, Indent, SlotTracker); +} + +void VPReplicateRecipe::print(raw_ostream &O, const Twine &Indent, + VPSlotTracker &SlotTracker) const { O << " +\n" << Indent << "\"" << (IsUniform ? "CLONE " : "REPLICATE ") << VPlanIngredient(Ingredient); @@ -731,6 +782,12 @@ } void VPPredInstPHIRecipe::print(raw_ostream &O, const Twine &Indent) const { + VPSlotTracker SlotTracker; + print(O, Indent, SlotTracker); +} + +void VPPredInstPHIRecipe::print(raw_ostream &O, const Twine &Indent, + VPSlotTracker &SlotTracker) const { O << " +\n" << Indent << "\"PHI-PREDICATED-INSTRUCTION " << VPlanIngredient(PredInst) << "\\l\""; @@ -738,13 +795,19 @@ void VPWidenMemoryInstructionRecipe::print(raw_ostream &O, const Twine &Indent) const { + VPSlotTracker SlotTracker; + print(O, Indent, SlotTracker); +} + +void VPWidenMemoryInstructionRecipe::print(raw_ostream &O, const Twine &Indent, + VPSlotTracker &SlotTracker) const { O << " +\n" << Indent << "\"WIDEN " << VPlanIngredient(&Instr); O << ", "; - getAddr()->printAsOperand(O); + getAddr()->printAsOperand(O, SlotTracker); VPValue *Mask = getMask(); if (Mask) { O << ", "; - Mask->printAsOperand(O); + Mask->printAsOperand(O, SlotTracker); } O << "\\l\""; } @@ -758,6 +821,10 @@ User->setOperand(I, New); } +void VPValue::printAsOperand(raw_ostream &OS, VPSlotTracker &Tracker) const { + OS << "%vp" << Tracker.getSlot(this); +} + void VPInterleavedAccessInfo::visitRegion(VPRegionBlock *Region, Old2NewTy &Old2New, InterleavedAccessInfo &IAI) { @@ -803,3 +870,48 @@ Old2NewTy Old2New; visitRegion(cast(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(VPBB)) + assignSlots(Region); + else + assignSlots(cast(VPBB)); +} + +void VPSlotTracker::assignSlots(const VPRegionBlock *Region) { + ReversePostOrderTraversal 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(&Recipe)) + assignSlot(VPI); + } +} + +void VPSlotTracker::assignSlots(const VPlan &Plan) { + + for (const VPValue *V : Plan.VPExternalDefs) + assignSlot(V); + + for (auto &E : Plan.Value2VPValue) + if (!isa(E.second)) + assignSlot(E.second); + + for (const VPValue *V : Plan.VPCBVs) + assignSlot(V); + + if (Plan.BackedgeTakenCount) + assignSlot(Plan.BackedgeTakenCount); + + ReversePostOrderTraversal RPOT(Plan.getEntry()); + for (const VPBlockBase *Block : RPOT) + assignSlots(Block); +} diff --git a/llvm/lib/Transforms/Vectorize/VPlanValue.h b/llvm/lib/Transforms/Vectorize/VPlanValue.h --- a/llvm/lib/Transforms/Vectorize/VPlanValue.h +++ b/llvm/lib/Transforms/Vectorize/VPlanValue.h @@ -31,6 +31,8 @@ // Forward declarations. class VPUser; +class VPSlotTracker; + // 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 // coming from the input IR, instructions which VPlan will generate if executed @@ -85,9 +87,8 @@ /// for any other purpose, as the values may change as LLVM evolves. unsigned getVPValueID() const { return SubclassID; } - void printAsOperand(raw_ostream &OS) const { - OS << "%vp" << (unsigned short)(unsigned long long)this; - } + void printAsOperand(raw_ostream &OS, VPSlotTracker &Tracker) const; + void print(raw_ostream &OS, VPSlotTracker &Tracker) const; unsigned getNumUsers() const { return Users.size(); } void addUser(VPUser &User) { Users.push_back(&User); } @@ -124,7 +125,7 @@ typedef DenseMap Value2VPValueTy; typedef DenseMap VPValue2ValueTy; -raw_ostream &operator<<(raw_ostream &OS, const VPValue &V); +// raw_ostream &operator<<(raw_ostream &OS, const VPValue &V); /// This class augments VPValue with operands which provide the inverse def-use /// edges from VPValue's users to their defs. @@ -180,6 +181,34 @@ 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 Slots; + unsigned NextSlot = 0; + + void assignSlots(const VPBlockBase *VPBB); + void assignSlots(const VPRegionBlock *Region); + void assignSlots(const VPBasicBlock *VPBB); + void assignSlot(const VPValue *V); + +public: + VPSlotTracker() {} + + void assignSlots(const VPlan &Plan); + + unsigned getSlot(const VPValue *V) const { + auto I = Slots.find(V); + assert(I != Slots.end() && "Not slot for VPValue!"); + return I->second; + } +}; } // namespace llvm