From: James Molloy Date: Thu, 17 Oct 2019 08:34:29 +0000 (+0000) Subject: [DFAPacketizer] Use DFAEmitter. NFC. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9d008e4cc95d49cfd78451978390e759aad9c333;p=llvm [DFAPacketizer] Use DFAEmitter. NFC. Summary: This is a NFC change that removes the NFA->DFA construction and emission logic from DFAPacketizerEmitter and instead uses the generic DFAEmitter logic. This allows DFAPacketizer to use the Automaton class from Support and remove a bunch of logic there too. After this patch, DFAPacketizer is mostly logic for grepping Itineraries and collecting functional units, with no state machine logic. This will allow us to modernize by removing the 16-functional-unit limit and supporting non-itinerary functional units. This is all for followup patches. Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D68992 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@375086 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/CodeGen/DFAPacketizer.h b/include/llvm/CodeGen/DFAPacketizer.h index dad19fee488..77ada7fda92 100644 --- a/include/llvm/CodeGen/DFAPacketizer.h +++ b/include/llvm/CodeGen/DFAPacketizer.h @@ -28,6 +28,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/ScheduleDAGMutation.h" +#include "llvm/Support/Automaton.h" #include #include #include @@ -76,59 +77,26 @@ using DFAStateInput = int64_t; class DFAPacketizer { private: - using UnsignPair = std::pair; - const InstrItineraryData *InstrItins; - int CurrentState = 0; - const DFAStateInput (*DFAStateInputTable)[2]; - const unsigned *DFAStateEntryTable; - const unsigned (*DFAResourceTransitionTable)[2]; - const unsigned *DFAResourceTransitionEntryTable; - - // CachedTable is a map from to ToState. - DenseMap CachedTable; - // CachedResourceTransitions is a map from to a list of - // resource transitions. - DenseMap> - CachedResourceTransitions; - - // Read the DFA transition table and update CachedTable. - void ReadTable(unsigned state); - - bool TrackResources = false; - // State for the current packet. Every entry is a possible packing of the - // bundle, indexed by cumulative resource state. Each entry is a list of the - // cumulative resource states after packing each instruction. For example if - // we pack I0: [0x4] and I1: [0x2] we will end up with: - // ResourceStates[0x6] = [0x4, 0x6] - DenseMap> ResourceStates; + Automaton A; public: - DFAPacketizer(const InstrItineraryData *I, const DFAStateInput (*SIT)[2], - const unsigned *SET, - const unsigned (*RTT)[2] = nullptr, - const unsigned *RTET = nullptr); + DFAPacketizer(const InstrItineraryData *InstrItins, Automaton a) : + InstrItins(InstrItins), A(std::move(a)) { + // Start off with resource tracking disabled. + A.enableTranscription(false); + } // Reset the current state to make all resources available. void clearResources() { - CurrentState = 0; - ResourceStates.clear(); - ResourceStates[0] = {}; + A.reset(); } // Set whether this packetizer should track not just whether instructions // can be packetized, but also which functional units each instruction ends up // using after packetization. void setTrackResources(bool Track) { - if (Track != TrackResources) { - TrackResources = Track; - if (Track) { - CachedTable.clear(); - assert(DFAResourceTransitionEntryTable); - assert(DFAResourceTransitionTable); - } - } - assert(CurrentState == 0 && "Can only change TrackResources on an empty packetizer!"); + A.enableTranscription(Track); } // Return the DFAInput for an instruction class. diff --git a/include/llvm/Support/Automaton.h b/include/llvm/Support/Automaton.h index 5fe0824017d..a5a4aef0130 100644 --- a/include/llvm/Support/Automaton.h +++ b/include/llvm/Support/Automaton.h @@ -167,6 +167,8 @@ template class Automaton { std::unique_ptr Transcriber; /// The initial DFA state is 1. uint64_t State = 1; + /// True if we should transcribe and false if not (even if Transcriber is defined). + bool Transcribe; public: /// Create an automaton. @@ -186,6 +188,7 @@ public: if (!TranscriptionTable.empty()) Transcriber = std::make_unique(TranscriptionTable); + Transcribe = Transcriber != nullptr; for (const auto &I : Transitions) // Greedily read and cache the transition table. M.emplace(std::make_pair(I.FromDfaState, I.Action), @@ -199,6 +202,15 @@ public: Transcriber->reset(); } + /// Enable or disable transcription. Transcription is only available if + /// TranscriptionTable was provided to the constructor. + void enableTranscription(bool Enable = true) { + assert(Transcriber && + "Transcription is only available if TranscriptionTable was provided " + "to the Automaton constructor"); + Transcribe = Enable; + } + /// Transition the automaton based on input symbol A. Return true if the /// automaton transitioned to a valid state, false if the automaton /// transitioned to an invalid state. @@ -209,17 +221,24 @@ public: auto I = M.find({State, A}); if (I == M.end()) return false; - if (Transcriber) + if (Transcriber && Transcribe) Transcriber->transition(I->second.second); State = I->second.first; return true; } + /// Return true if the automaton can be transitioned based on input symbol A. + bool canAdd(const ActionT &A) { + auto I = M.find({State, A}); + return I != M.end(); + } + /// Obtain a set of possible paths through the input nondeterministic /// automaton that could be obtained from the sequence of input actions /// presented to this deterministic automaton. ArrayRef getNfaPaths() { - assert(Transcriber && "Can only obtain NFA paths if transcribing!"); + assert(Transcriber && Transcribe && + "Can only obtain NFA paths if transcribing!"); return Transcriber->getPaths(); } }; diff --git a/lib/CodeGen/DFAPacketizer.cpp b/lib/CodeGen/DFAPacketizer.cpp index 500ae68d007..d31f9f8d174 100644 --- a/lib/CodeGen/DFAPacketizer.cpp +++ b/lib/CodeGen/DFAPacketizer.cpp @@ -72,52 +72,13 @@ static DFAInput getDFAInsnInput(const std::vector &InsnClass) { // -------------------------------------------------------------------- -DFAPacketizer::DFAPacketizer(const InstrItineraryData *I, - const DFAStateInput (*SIT)[2], const unsigned *SET, - const unsigned (*RTT)[2], - const unsigned *RTET) - : InstrItins(I), DFAStateInputTable(SIT), DFAStateEntryTable(SET), - DFAResourceTransitionTable(RTT), DFAResourceTransitionEntryTable(RTET) { - // Make sure DFA types are large enough for the number of terms & resources. - static_assert((DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) <= - (8 * sizeof(DFAInput)), - "(DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) too big for DFAInput"); - static_assert( - (DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) <= (8 * sizeof(DFAStateInput)), - "(DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) too big for DFAStateInput"); - clearResources(); -} - -// Read the DFA transition table and update CachedTable. -// -// Format of the transition tables: -// DFAStateInputTable[][2] = pairs of for all valid -// transitions -// DFAStateEntryTable[i] = Index of the first entry in DFAStateInputTable -// for the ith state -// -void DFAPacketizer::ReadTable(unsigned int state) { - unsigned ThisStateIdx = DFAStateEntryTable[state]; - unsigned NextStateIdxInTable = DFAStateEntryTable[state + 1]; - // Early exit in case CachedTable has already contains this - // state's transitions. - if (CachedTable.count(UnsignPair(state, DFAStateInputTable[ThisStateIdx][0]))) - return; - - for (unsigned TransitionIdx = ThisStateIdx; - TransitionIdx < NextStateIdxInTable; TransitionIdx++) { - auto TransitionPair = - UnsignPair(state, DFAStateInputTable[TransitionIdx][0]); - CachedTable[TransitionPair] = DFAStateInputTable[TransitionIdx][1]; - - if (TrackResources) { - unsigned I = DFAResourceTransitionEntryTable[TransitionIdx]; - unsigned E = DFAResourceTransitionEntryTable[TransitionIdx + 1]; - CachedResourceTransitions[TransitionPair] = makeArrayRef( - &DFAResourceTransitionTable[I], &DFAResourceTransitionTable[E]); - } - } -} +// Make sure DFA types are large enough for the number of terms & resources. +static_assert((DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) <= + (8 * sizeof(DFAInput)), + "(DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) too big for DFAInput"); +static_assert( + (DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) <= (8 * sizeof(DFAStateInput)), + "(DFA_MAX_RESTERMS * DFA_MAX_RESOURCES) too big for DFAStateInput"); // Return the DFAInput for an instruction class. DFAInput DFAPacketizer::getInsnInput(unsigned InsnClass) { @@ -143,9 +104,7 @@ DFAInput DFAPacketizer::getInsnInput(const std::vector &InsnClass) { bool DFAPacketizer::canReserveResources(const MCInstrDesc *MID) { unsigned InsnClass = MID->getSchedClass(); DFAInput InsnInput = getInsnInput(InsnClass); - UnsignPair StateTrans = UnsignPair(CurrentState, InsnInput); - ReadTable(CurrentState); - return CachedTable.count(StateTrans) != 0; + return A.canAdd(InsnInput); } // Reserve the resources occupied by a MCInstrDesc and change the current @@ -153,20 +112,7 @@ bool DFAPacketizer::canReserveResources(const MCInstrDesc *MID) { void DFAPacketizer::reserveResources(const MCInstrDesc *MID) { unsigned InsnClass = MID->getSchedClass(); DFAInput InsnInput = getInsnInput(InsnClass); - UnsignPair StateTrans = UnsignPair(CurrentState, InsnInput); - ReadTable(CurrentState); - - if (TrackResources) { - DenseMap> NewResourceStates; - for (const auto &KV : CachedResourceTransitions[StateTrans]) { - assert(ResourceStates.count(KV[0])); - NewResourceStates[KV[1]] = ResourceStates[KV[0]]; - NewResourceStates[KV[1]].push_back(KV[1]); - } - ResourceStates = NewResourceStates; - } - assert(CachedTable.count(StateTrans) != 0); - CurrentState = CachedTable[StateTrans]; + A.add(InsnInput); } // Check if the resources occupied by a machine instruction are available @@ -184,10 +130,9 @@ void DFAPacketizer::reserveResources(MachineInstr &MI) { } unsigned DFAPacketizer::getUsedResources(unsigned InstIdx) { - assert(TrackResources && "getUsedResources requires resource tracking!"); - // Assert that there is at least one example of a valid bundle format. - assert(!ResourceStates.empty() && "Invalid bundle!"); - SmallVectorImpl &RS = ResourceStates.begin()->second; + ArrayRef NfaPaths = A.getNfaPaths(); + assert(!NfaPaths.empty() && "Invalid bundle!"); + const NfaPath &RS = NfaPaths.front(); // RS stores the cumulative resources used up to and including the I'th // instruction. The 0th instruction is the base case. diff --git a/test/CodeGen/Hexagon/packetizer-resources.ll b/test/CodeGen/Hexagon/packetizer-resources.ll index 9bd0cb1f5fa..6b705396b5d 100644 --- a/test/CodeGen/Hexagon/packetizer-resources.ll +++ b/test/CodeGen/Hexagon/packetizer-resources.ll @@ -2,8 +2,8 @@ ; REQUIRES: asserts ; CHECK: Finalizing packet: -; CHECK-NEXT: * [res:0x8] renamable $r1 = S2_vsplatrb renamable $r0 -; CHECK-NEXT: * [res:0x4] renamable $d1 = S2_vsplatrh killed renamable $r0 +; CHECK-NEXT: * [res:0x4] renamable $r1 = S2_vsplatrb renamable $r0 +; CHECK-NEXT: * [res:0x8] renamable $d1 = S2_vsplatrh killed renamable $r0 target triple = "hexagon" diff --git a/utils/TableGen/DFAPacketizerEmitter.cpp b/utils/TableGen/DFAPacketizerEmitter.cpp index 8ac187e86ea..0d3c6fdc933 100644 --- a/utils/TableGen/DFAPacketizerEmitter.cpp +++ b/utils/TableGen/DFAPacketizerEmitter.cpp @@ -17,6 +17,7 @@ #define DEBUG_TYPE "dfa-emitter" #include "CodeGenTarget.h" +#include "DFAEmitter.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" @@ -162,132 +163,6 @@ public: void run(raw_ostream &OS); }; - -// -// State represents the usage of machine resources if the packet contains -// a set of instruction classes. -// -// Specifically, currentState is a set of bit-masks. -// The nth bit in a bit-mask indicates whether the nth resource is being used -// by this state. The set of bit-masks in a state represent the different -// possible outcomes of transitioning to this state. -// For example: consider a two resource architecture: resource L and resource M -// with three instruction classes: L, M, and L_or_M. -// From the initial state (currentState = 0x00), if we add instruction class -// L_or_M we will transition to a state with currentState = [0x01, 0x10]. This -// represents the possible resource states that can result from adding a L_or_M -// instruction -// -// Another way of thinking about this transition is we are mapping a NDFA with -// two states [0x01] and [0x10] into a DFA with a single state [0x01, 0x10]. -// -// A State instance also contains a collection of transitions from that state: -// a map from inputs to new states. -// -class State { - public: - static int currentStateNum; - // stateNum is the only member used for equality/ordering, all other members - // can be mutated even in const State objects. - const int stateNum; - mutable bool isInitial; - mutable std::set stateInfo; - - struct TransitionInfo { - // Maps from a resource bitmask in this state to the equivalent resource - // bitmap in the transitioned-to state. This is a 1-to-N mapping. - std::vector> ResourceTransitions; - const State *S; - }; - using TransitionMap = std::map, TransitionInfo>; - mutable TransitionMap Transitions; - - State(); - - bool operator<(const State &s) const { - return stateNum < s.stateNum; - } - - // - // canMaybeAddInsnClass - Quickly verifies if an instruction of type InsnClass - // may be a valid transition from this state i.e., can an instruction of type - // InsnClass be added to the packet represented by this state. - // - // Note that for multiple stages, this quick check does not take into account - // any possible resource competition between the stages themselves. That is - // enforced in AddInsnClassStages which checks the cross product of all - // stages for resource availability (which is a more involved check). - // - bool canMaybeAddInsnClass(std::vector &InsnClass, - std::map &ComboBitToBitsMap) const; - - // - // AddInsnClass - Return all combinations of resource reservation - // which are possible from this state (PossibleStates). - // - // PossibleStates is the set of valid resource states that ensue from valid - // transitions. - // - // TransitionInfo maps from a resource bitmask B in this state to a resource - // bitmask B' in PossibleStates. This is a one-to-many (or none) mapping. - // - void AddInsnClass( - std::vector &InsnClass, - std::map &ComboBitToBitsMap, - std::set &PossibleStates, - std::vector> &TransitionInfo) const; - - // - // AddInsnClassStages - Return all combinations of resource reservation - // resulting from the cross product of all stages for this InsnClass - // which are possible from this state (PossibleStates). - // - void AddInsnClassStages(std::vector &InsnClass, - std::map &ComboBitToBitsMap, - unsigned chkstage, unsigned numstages, - unsigned prevState, unsigned origState, - DenseSet &VisitedResourceStates) const; - - // - // addTransition - Add a transition from this state given the input InsnClass. - // - void addTransition( - std::vector InsnClass, const State *To, - const std::vector> &TransitionInfo) const; - - // - // hasTransition - Returns true if there is a transition from this state - // given the input InsnClass - // - bool hasTransition(std::vector InsnClass) const; -}; - -// -// class DFA: deterministic finite automaton for processor resource tracking. -// -class DFA { -public: - DFA() = default; - - // Set of states. Need to keep this sorted to emit the transition table. - typedef std::set StateSet; - StateSet states; - - State *currentState = nullptr; - - // - // Modify the DFA. - // - const State &newState(); - - // - // writeTable: Print out a table representing the DFA. - // - void writeTableAndAPI(raw_ostream &OS, const std::string &ClassName, - int numInsnClasses = 0, - int maxResources = 0, int numCombos = 0, int maxStages = 0); -}; - } // end anonymous namespace #ifndef NDEBUG @@ -307,22 +182,6 @@ void dbgsInsnClass(const std::vector &InsnClass) { LLVM_DEBUG(dbgs() << " (input: 0x" << Twine::utohexstr(InsnInput) << ")"); } -// -// dbgsStateInfo - When debugging, print the set of state info. -// -void dbgsStateInfo(const std::set &stateInfo) { - LLVM_DEBUG(dbgs() << "StateInfo: "); - unsigned i = 0; - for (std::set::iterator SI = stateInfo.begin(); - SI != stateInfo.end(); ++SI, ++i) { - unsigned thisState = *SI; - if (i > 0) { - LLVM_DEBUG(dbgs() << ", "); - } - LLVM_DEBUG(dbgs() << "0x" << Twine::utohexstr(thisState)); - } -} - // // dbgsIndent - When debugging, indent by the specified amount. // @@ -333,339 +192,9 @@ void dbgsIndent(unsigned indent) { } #endif // NDEBUG -// -// Constructors and destructors for State and DFA -// -State::State() : - stateNum(currentStateNum++), isInitial(false) {} - -// -// addTransition - Add a transition from this state given the input InsnClass -// -void State::addTransition( - std::vector InsnClass, const State *To, - const std::vector> &TransitionInfo) const { - assert(!Transitions.count(InsnClass) && - "Cannot have multiple transitions for the same input"); - Transitions[InsnClass] = {TransitionInfo, To}; -} - -// -// hasTransition - Returns true if there is a transition from this state -// given the input InsnClass -// -bool State::hasTransition(std::vector InsnClass) const { - return Transitions.count(InsnClass) > 0; -} - -// -// AddInsnClass - Return all combinations of resource reservation -// which are possible from this state (PossibleStates). -// -// PossibleStates is the set of valid resource states that ensue from valid -// transitions. -// -void State::AddInsnClass( - std::vector &InsnClass, - std::map &ComboBitToBitsMap, - std::set &PossibleStates, - std::vector> &TransitionInfo) const { - // - // Iterate over all resource states in currentState. - // - unsigned numstages = InsnClass.size(); - assert((numstages > 0) && "InsnClass has no stages"); - - for (std::set::iterator SI = stateInfo.begin(); - SI != stateInfo.end(); ++SI) { - unsigned ThisState = *SI; - - DenseSet VisitedResourceStates; - - LLVM_DEBUG(dbgs() << " thisState: 0x" << Twine::utohexstr(ThisState) - << "\n"); - AddInsnClassStages(InsnClass, ComboBitToBitsMap, numstages - 1, numstages, - ThisState, ThisState, VisitedResourceStates); - for (unsigned NewState : VisitedResourceStates) { - PossibleStates.insert(NewState); - TransitionInfo.emplace_back(ThisState, NewState); - } - } -} - -void State::AddInsnClassStages( - std::vector &InsnClass, - std::map &ComboBitToBitsMap, unsigned chkstage, - unsigned numstages, unsigned prevState, unsigned origState, - DenseSet &VisitedResourceStates) const { - assert((chkstage < numstages) && "AddInsnClassStages: stage out of range"); - unsigned thisStage = InsnClass[chkstage]; - - LLVM_DEBUG({ - dbgsIndent((1 + numstages - chkstage) << 1); - dbgs() << "AddInsnClassStages " << chkstage << " (0x" - << Twine::utohexstr(thisStage) << ") from "; - dbgsInsnClass(InsnClass); - dbgs() << "\n"; - }); - - // - // Iterate over all possible resources used in thisStage. - // For ex: for thisStage = 0x11, all resources = {0x01, 0x10}. - // - for (unsigned int j = 0; j < DFA_MAX_RESOURCES; ++j) { - unsigned resourceMask = (0x1 << j); - if (resourceMask & thisStage) { - unsigned combo = ComboBitToBitsMap[resourceMask]; - if (combo && ((~prevState & combo) != combo)) { - LLVM_DEBUG(dbgs() << "\tSkipped Add 0x" << Twine::utohexstr(prevState) - << " - combo op 0x" << Twine::utohexstr(resourceMask) - << " (0x" << Twine::utohexstr(combo) - << ") cannot be scheduled\n"); - continue; - } - // - // For each possible resource used in thisStage, generate the - // resource state if that resource was used. - // - unsigned ResultingResourceState = prevState | resourceMask | combo; - LLVM_DEBUG({ - dbgsIndent((2 + numstages - chkstage) << 1); - dbgs() << "0x" << Twine::utohexstr(prevState) << " | 0x" - << Twine::utohexstr(resourceMask); - if (combo) - dbgs() << " | 0x" << Twine::utohexstr(combo); - dbgs() << " = 0x" << Twine::utohexstr(ResultingResourceState) << " "; - }); - - // - // If this is the final stage for this class - // - if (chkstage == 0) { - // - // Check if the resulting resource state can be accommodated in this - // packet. - // We compute resource OR prevState (originally started as origState). - // If the result of the OR is different than origState, it implies - // that there is at least one resource that can be used to schedule - // thisStage in the current packet. - // Insert ResultingResourceState into PossibleStates only if we haven't - // processed ResultingResourceState before. - // - if (ResultingResourceState != prevState) { - if (VisitedResourceStates.count(ResultingResourceState) == 0) { - VisitedResourceStates.insert(ResultingResourceState); - LLVM_DEBUG(dbgs() - << "\tResultingResourceState: 0x" - << Twine::utohexstr(ResultingResourceState) << "\n"); - } else { - LLVM_DEBUG(dbgs() << "\tSkipped Add - state already seen\n"); - } - } else { - LLVM_DEBUG(dbgs() - << "\tSkipped Add - no final resources available\n"); - } - } else { - // - // If the current resource can be accommodated, check the next - // stage in InsnClass for available resources. - // - if (ResultingResourceState != prevState) { - LLVM_DEBUG(dbgs() << "\n"); - AddInsnClassStages(InsnClass, ComboBitToBitsMap, chkstage - 1, - numstages, ResultingResourceState, origState, - VisitedResourceStates); - } else { - LLVM_DEBUG(dbgs() << "\tSkipped Add - no resources available\n"); - } - } - } - } -} - -// -// canMaybeAddInsnClass - Quickly verifies if an instruction of type InsnClass -// may be a valid transition from this state i.e., can an instruction of type -// InsnClass be added to the packet represented by this state. -// -// Note that this routine is performing conservative checks that can be -// quickly executed acting as a filter before calling AddInsnClassStages. -// Any cases allowed through here will be caught later in AddInsnClassStages -// which performs the more expensive exact check. -// -bool State::canMaybeAddInsnClass(std::vector &InsnClass, - std::map &ComboBitToBitsMap) const { - for (std::set::const_iterator SI = stateInfo.begin(); - SI != stateInfo.end(); ++SI) { - // Check to see if all required resources are available. - bool available = true; - - // Inspect each stage independently. - // note: This is a conservative check as we aren't checking for - // possible resource competition between the stages themselves - // The full cross product is examined later in AddInsnClass. - for (unsigned i = 0; i < InsnClass.size(); ++i) { - unsigned resources = *SI; - if ((~resources & InsnClass[i]) == 0) { - available = false; - break; - } - // Make sure _all_ resources for a combo function are available. - // note: This is a quick conservative check as it won't catch an - // unscheduleable combo if this stage is an OR expression - // containing a combo. - // These cases are caught later in AddInsnClass. - unsigned combo = ComboBitToBitsMap[InsnClass[i]]; - if (combo && ((~resources & combo) != combo)) { - LLVM_DEBUG(dbgs() << "\tSkipped canMaybeAdd 0x" - << Twine::utohexstr(resources) << " - combo op 0x" - << Twine::utohexstr(InsnClass[i]) << " (0x" - << Twine::utohexstr(combo) - << ") cannot be scheduled\n"); - available = false; - break; - } - } - - if (available) { - return true; - } - } - return false; -} - -const State &DFA::newState() { - auto IterPair = states.insert(State()); - assert(IterPair.second && "State already exists"); - return *IterPair.first; -} - -int State::currentStateNum = 0; - DFAPacketizerEmitter::DFAPacketizerEmitter(RecordKeeper &R): TargetName(CodeGenTarget(R).getName()), Records(R) {} -// -// writeTableAndAPI - Print out a table representing the DFA and the -// associated API to create a DFA packetizer. -// -// Format: -// DFAStateInputTable[][2] = pairs of for all valid -// transitions. -// DFAStateEntryTable[i] = Index of the first entry in DFAStateInputTable for -// the ith state. -// -// -void DFA::writeTableAndAPI(raw_ostream &OS, const std::string &TargetName, - int numInsnClasses, - int maxResources, int numCombos, int maxStages) { - unsigned numStates = states.size(); - - LLVM_DEBUG(dbgs() << "-------------------------------------------------------" - "----------------------\n"); - LLVM_DEBUG(dbgs() << "writeTableAndAPI\n"); - LLVM_DEBUG(dbgs() << "Total states: " << numStates << "\n"); - - OS << "\n// " << TargetName << "DFAStateInputTable[][2] = " - << "pairs of for all valid\n"; - OS << "// transitions.\n"; - OS << "// " << numStates << "\tstates\n"; - OS << "// " << numInsnClasses << "\tinstruction classes\n"; - OS << "// " << maxResources << "\tresources max\n"; - OS << "// " << numCombos << "\tcombo resources\n"; - OS << "// " << maxStages << "\tstages max\n"; - OS << "const " << DFA_TBLTYPE << " " - << TargetName << "DFAStateInputTable[][2] = {\n"; - - // This table provides a map to the beginning of the transitions for State s - // in DFAStateInputTable. - std::vector StateEntry(numStates+1); - static const std::string SentinelEntry = "{-1, -1}"; - - // Tracks the total valid transitions encountered so far. It is used - // to construct the StateEntry table. - int ValidTransitions = 0; - DFA::StateSet::iterator SI = states.begin(); - for (unsigned i = 0; i < numStates; ++i, ++SI) { - assert ((SI->stateNum == (int) i) && "Mismatch in state numbers"); - StateEntry[i] = ValidTransitions; - for (State::TransitionMap::iterator - II = SI->Transitions.begin(), IE = SI->Transitions.end(); - II != IE; ++II) { - OS << "{0x" << Twine::utohexstr(getDFAInsnInput(II->first)) << ", " - << II->second.S->stateNum << "},\t"; - } - ValidTransitions += SI->Transitions.size(); - - OS << " // state " << i << ": " << StateEntry[i]; - if (StateEntry[i] != (ValidTransitions-1)) { // More than one transition. - OS << "-" << (ValidTransitions-1); - } - OS << "\n"; - } - - // Print out a sentinel entry at the end of the StateInputTable. This is - // needed to iterate over StateInputTable in DFAPacketizer::ReadTable() - OS << SentinelEntry << "\t"; - OS << " // state " << numStates << ": " << ValidTransitions; - OS << "\n"; - - OS << "};\n\n"; - OS << "// " << TargetName << "DFAStateEntryTable[i] = " - << "Index of the first entry in DFAStateInputTable for\n"; - OS << "// " - << "the ith state.\n"; - OS << "// " << numStates << " states\n"; - OS << "const unsigned int " << TargetName << "DFAStateEntryTable[] = {\n"; - - unsigned lastState = 0; - for (unsigned i = 0; i < numStates; ++i) { - if (i && ((i % 10) == 0)) { - lastState = i-1; - OS << " // states " << (i-10) << ":" << lastState << "\n"; - } - OS << StateEntry[i] << ", "; - } - // Print out the index to the sentinel entry in StateInputTable - OS << ValidTransitions << ", "; - OS << " // states " << (lastState+1) << ":" << numStates << "\n"; - OS << "};\n"; - - // Generate the resource transition table. - OS << "const unsigned " << TargetName - << "DFAResourceTransitionTable[][2] = { \n"; - int N = 0; - StateEntry.clear(); - for (const State &S : states) { - for (auto &KV : S.Transitions) { - StateEntry.push_back(N); - for (std::pair &T : KV.second.ResourceTransitions) { - OS << "{0x" << utohexstr(T.first) << ", 0x" << utohexstr(T.second) - << "}, "; - ++N; - } - } - OS << "\n "; - } - // Add a sentinel entry to terminate the search. - StateEntry.push_back(N); - OS << "\n {~0U,~0U}\n};\n\n"; - - OS << "// " << TargetName << "DFAResourceTransitionEntryTable[i] = " - << "Index of the first entry in DFAResourceTransitionTable for\n"; - OS << "// the ith transition.\n"; - OS << "const unsigned int " << TargetName - << "DFAResourceTransitionEntryTable[] = { \n"; - - N = 0; - for (int S : StateEntry) { - OS << S << ","; - if (N++ % 10 == 0) - OS << "\n "; - } - OS << "\n ~0U\n};\n"; -} - // // collectAllFuncUnits - Construct a map of function unit names to bits. // @@ -900,8 +429,7 @@ void DFAPacketizerEmitter::emitForItineraries( std::map ComboBitToBitsMap; std::vector ComboFuncList = Records.getAllDerivedDefinitions("ComboFuncUnits"); - int numCombos = collectAllComboFuncs(ComboFuncList, - FUNameToBitsMap, ComboBitToBitsMap, OS); + collectAllComboFuncs(ComboFuncList, FUNameToBitsMap, ComboBitToBitsMap, OS); // // Collect the itineraries. @@ -932,119 +460,89 @@ void DFAPacketizerEmitter::emitForItineraries( FUNameToBitsMap, ItinDataList, maxStages, OS); } - // - // Run a worklist algorithm to generate the DFA. - // - DFA D; - const State *Initial = &D.newState(); - Initial->isInitial = true; - Initial->stateInfo.insert(0x0); - SmallVector WorkList; - std::map, const State*> Visited; - - WorkList.push_back(Initial); - - // - // Worklist algorithm to create a DFA for processor resource tracking. - // C = {set of InsnClasses} - // Begin with initial node in worklist. Initial node does not have - // any consumed resources, - // ResourceState = 0x0 - // Visited = {} - // While worklist != empty - // S = first element of worklist - // For every instruction class C - // if we can accommodate C in S: - // S' = state with resource states = {S Union C} - // Add a new transition: S x C -> S' - // If S' is not in Visited: - // Add S' to worklist - // Add S' to Visited - // - while (!WorkList.empty()) { - const State *current = WorkList.pop_back_val(); - LLVM_DEBUG({ - dbgs() << "---------------------\n"; - dbgs() << "Processing state: " << current->stateNum << " - "; - dbgsStateInfo(current->stateInfo); - dbgs() << "\n"; - }); - for (unsigned i = 0; i < allInsnClasses.size(); i++) { - std::vector InsnClass = allInsnClasses[i]; - LLVM_DEBUG({ - dbgs() << i << " "; - dbgsInsnClass(InsnClass); - dbgs() << "\n"; - }); - - std::set NewStateResources; - // - // If we haven't already created a transition for this input - // and the state can accommodate this InsnClass, create a transition. - // - if (!current->hasTransition(InsnClass) && - current->canMaybeAddInsnClass(InsnClass, ComboBitToBitsMap)) { - const State *NewState = nullptr; - std::vector> TransitionInfo; - current->AddInsnClass(InsnClass, ComboBitToBitsMap, NewStateResources, - TransitionInfo); - if (NewStateResources.empty()) { - LLVM_DEBUG(dbgs() << " Skipped - no new states generated\n"); - continue; + // The type of a state in the nondeterministic automaton we're defining. + using NfaStateTy = unsigned; + + // Given a resource state, return all resource states by applying + // InsnClass. + auto applyInsnClass = [&](ArrayRef InsnClass, + NfaStateTy State) -> std::deque { + std::deque V(1, State); + // Apply every stage in the class individually. + for (unsigned Stage : InsnClass) { + // Apply this stage to every existing member of V in turn. + size_t Sz = V.size(); + for (unsigned I = 0; I < Sz; ++I) { + unsigned S = V.front(); + V.pop_front(); + + // For this stage, state combination, try all possible resources. + for (unsigned J = 0; J < DFA_MAX_RESOURCES; ++J) { + unsigned ResourceMask = 1U << J; + if ((ResourceMask & Stage) == 0) + // This resource isn't required by this stage. + continue; + unsigned Combo = ComboBitToBitsMap[ResourceMask]; + if (Combo && ((~S & Combo) != Combo)) + // This combo units bits are not available. + continue; + unsigned ResultingResourceState = S | ResourceMask | Combo; + if (ResultingResourceState == S) + continue; + V.push_back(ResultingResourceState); } + } + } + return V; + }; - LLVM_DEBUG({ - dbgs() << "\t"; - dbgsStateInfo(NewStateResources); - dbgs() << "\n"; - }); - - // - // If we have seen this state before, then do not create a new state. - // - auto VI = Visited.find(NewStateResources); - if (VI != Visited.end()) { - NewState = VI->second; - LLVM_DEBUG({ - dbgs() << "\tFound existing state: " << NewState->stateNum - << " - "; - dbgsStateInfo(NewState->stateInfo); - dbgs() << "\n"; - }); - } else { - NewState = &D.newState(); - NewState->stateInfo = NewStateResources; - Visited[NewStateResources] = NewState; - WorkList.push_back(NewState); - LLVM_DEBUG({ - dbgs() << "\tAccepted new state: " << NewState->stateNum << " - "; - dbgsStateInfo(NewState->stateInfo); - dbgs() << "\n"; - }); - } + // Given a resource state, return a quick (conservative) guess as to whether + // InsnClass can be applied. This is a filter for the more heavyweight + // applyInsnClass. + auto canApplyInsnClass = [](ArrayRef InsnClass, + NfaStateTy State) -> bool { + for (unsigned Resources : InsnClass) { + if ((State | Resources) == State) + return false; + } + return true; + }; - current->addTransition(InsnClass, NewState, TransitionInfo); + DfaEmitter Emitter; + std::deque Worklist(1, 0); + std::set SeenStates; + SeenStates.insert(Worklist.front()); + while (!Worklist.empty()) { + NfaStateTy State = Worklist.front(); + Worklist.pop_front(); + for (unsigned i = 0; i < allInsnClasses.size(); i++) { + const std::vector &InsnClass = allInsnClasses[i]; + if (!canApplyInsnClass(InsnClass, State)) + continue; + for (unsigned NewState : applyInsnClass(InsnClass, State)) { + if (SeenStates.emplace(NewState).second) + Worklist.emplace_back(NewState); + Emitter.addTransition(State, NewState, getDFAInsnInput(InsnClass)); } } } - // Print out the table. - D.writeTableAndAPI(OS, TargetName + DFAName, numInsnClasses, maxResources, - numCombos, maxStages); - - OS << "} // end namespace llvm\n"; + OS << "} // end namespace llvm\n\n"; + OS << "namespace {\n"; + std::string TargetAndDFAName = TargetName + DFAName; + Emitter.emit(TargetAndDFAName, OS); + OS << "} // end anonymous namespace\n\n"; std::string SubTargetClassName = TargetName + "GenSubtargetInfo"; OS << "namespace llvm {\n"; OS << "DFAPacketizer *" << SubTargetClassName << "::" << "create" << DFAName << "DFAPacketizer(const InstrItineraryData *IID) const {\n" - << " return new DFAPacketizer(IID, " << TargetName << DFAName - << "DFAStateInputTable, " << TargetName << DFAName - << "DFAStateEntryTable, " << TargetName << DFAName - << "DFAResourceTransitionTable, " << TargetName << DFAName - << "DFAResourceTransitionEntryTable" - << ");\n}\n\n"; + << " Automaton A(ArrayRef<" << TargetAndDFAName + << "Transition>(" << TargetAndDFAName << "Transitions), " + << TargetAndDFAName << "TransitionInfo);\n" + << " return new DFAPacketizer(IID, std::move(A));\n" + << "\n}\n\n"; } namespace llvm {