diff --git a/include/llvm/Support/Automaton.h b/include/llvm/Support/Automaton.h index e945d74f936..c2b921311a8 100644 --- a/include/llvm/Support/Automaton.h +++ b/include/llvm/Support/Automaton.h @@ -154,42 +154,29 @@ public: }; } // namespace internal -// Type representing a transition in the DFA state. -// The action type can be a custom type. -template struct TransitionType { - using StateT = unsigned; - StateT FromDfaState; // The transitioned-from DFA state. - ActionT Action; // The input symbol that causes this transition. - StateT ToDfaState; // The transitioned-to DFA state. - unsigned InfoIdx; // Start index into TransitionInfo. -}; - /// A deterministic finite-state automaton. The automaton is defined in /// TableGen; this object drives an automaton defined by tblgen-emitted tables. /// /// An automaton accepts a sequence of input tokens ("actions"). This class is /// templated on the type of these actions. template class Automaton { - using TransitionT = TransitionType; - using TransitionKeyT = std::pair; - using StateT = typename TransitionT::StateT; /// Map from {State, Action} to {NewState, TransitionInfoIdx}. /// TransitionInfoIdx is used by the DfaTranscriber to analyze the transition. - ArrayRef TransitionMap; + /// FIXME: This uses a std::map because ActionT can be a pair type including + /// an enum. In particular DenseMapInfo must be defined to use + /// DenseMap here. + /// This is a shared_ptr to allow very quick copy-construction of Automata; this + /// state is immutable after construction so this is safe. + using MapTy = std::map, std::pair>; + std::shared_ptr M; /// An optional transcription object. This uses much more state than simply /// traversing the DFA for acceptance, so is heap allocated. std::shared_ptr Transcriber; /// The initial DFA state is 1. - StateT State = 1; + uint64_t State = 1; /// True if we should transcribe and false if not (even if Transcriber is defined). bool Transcribe; - static bool transitionLessThan(const TransitionT &A, - const TransitionKeyT &B) { - return std::make_pair(A.FromDfaState, A.Action) < B; - } - public: /// Create an automaton. /// \param Transitions The Transitions table as created by TableGen. Note that @@ -202,24 +189,21 @@ public: /// NFA taken by the DFA. NOTE: This is substantially more work than simply /// driving the DFA, so unless you require the getPaths() method leave this /// empty. - Automaton(ArrayRef Transitions, + template + Automaton(ArrayRef Transitions, ArrayRef TranscriptionTable = {}) { if (!TranscriptionTable.empty()) Transcriber = std::make_shared(TranscriptionTable); Transcribe = Transcriber != nullptr; - TransitionMap = Transitions; - assert(std::is_sorted(TransitionMap.begin(), TransitionMap.end(), - [](const TransitionT &A, const TransitionT &B) { - return std::make_pair(A.FromDfaState, A.Action) < - std::make_pair(B.FromDfaState, B.Action); - }) && - "The transitions array is expected to be sorted by FromDfaState and " - "Action"); + M = std::make_shared(); + for (const auto &I : Transitions) + // Greedily read and cache the transition table. + M->emplace(std::make_pair(I.FromDfaState, I.Action), + std::make_pair(I.ToDfaState, I.InfoIdx)); } Automaton(const Automaton &Other) - : TransitionMap(Other.TransitionMap), State(Other.State), - Transcribe(Other.Transcribe) { + : M(Other.M), State(Other.State), Transcribe(Other.Transcribe) { // Transcriber is not thread-safe, so create a new instance on copy. if (Other.Transcriber) Transcriber = std::make_shared( @@ -249,22 +233,19 @@ public: /// If this function returns false, all methods are undefined until reset() is /// called. bool add(const ActionT &A) { - auto I = lower_bound(TransitionMap.begin(), TransitionMap.end(), - std::make_pair(State, A), transitionLessThan); - if (I == TransitionMap.end() || State != I->FromDfaState || A != I->Action) + auto I = M->find({State, A}); + if (I == M->end()) return false; if (Transcriber && Transcribe) - Transcriber->transition(I->InfoIdx); - State = I->ToDfaState; + 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 = lower_bound(TransitionMap.begin(), TransitionMap.end(), - std::make_pair(State, A), transitionLessThan); - return I != TransitionMap.end() && State == I->FromDfaState && - A == I->Action; + auto I = M->find({State, A}); + return I != M->end(); } /// Obtain a set of possible paths through the input nondeterministic diff --git a/utils/TableGen/DFAEmitter.cpp b/utils/TableGen/DFAEmitter.cpp index af05551c7c3..dd3db7c150b 100644 --- a/utils/TableGen/DFAEmitter.cpp +++ b/utils/TableGen/DFAEmitter.cpp @@ -131,9 +131,15 @@ void DfaEmitter::emit(StringRef Name, raw_ostream &OS) { OS << "}};\n\n"; OS << "// A transition in the generated " << Name << " DFA.\n"; - OS << "using " << Name << "Transition = TransitionType<"; + OS << "struct " << Name << "Transition {\n"; + OS << " unsigned FromDfaState; // The transitioned-from DFA state.\n"; + OS << " "; printActionType(OS); - OS << ">;\n\n"; + OS << " Action; // The input symbol that causes this transition.\n"; + OS << " unsigned ToDfaState; // The transitioned-to DFA state.\n"; + OS << " unsigned InfoIdx; // Start index into " << Name + << "TransitionInfo.\n"; + OS << "};\n\n"; OS << "// A table of DFA transitions, ordered by {FromDfaState, Action}.\n"; OS << "// The initial state is 1, not zero.\n";