mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 20:23:11 +01:00
5445e7fafa
Summary: This patch introduces -gen-automata, a backend for generating deterministic finite-state automata. DFAs are already generated by the -gen-dfa-packetizer backend. This backend is more generic and will hopefully be used to implement the DFA generation (and determinization) for the packetizer in the future. This backend allows not only generation of a DFA from an NFA (nondeterministic finite-state automaton), it also emits sidetables that allow a path through the DFA under a sequence of inputs to be analyzed, and the equivalent set of all possible NFA transitions extracted. This allows a user to not just answer "can my problem be solved?" but also "what is the solution?". Clearly this analysis is more expensive than just playing a DFA forwards so is opt-in. The DFAPacketizer has this behaviour already but this is a more compact and generic representation. Examples are bundled in unittests/TableGen/Automata.td. Some are trivial, but the BinPacking example is a stripped-down version of the original target problem I set out to solve, where we pack values (actually immediates) into bins (an immediate pool in a VLIW bundle) subject to a set of esoteric constraints. Reviewers: t.p.northover Subscribers: mgorny, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D67968 llvm-svn: 373718
96 lines
4.2 KiB
TableGen
96 lines
4.2 KiB
TableGen
//===- Automaton.td ----------------------------------------*- tablegen -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the key top-level classes needed to produce a reasonably
|
|
// generic finite-state automaton.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Define a record inheriting from GenericAutomaton to generate a reasonably
|
|
// generic finite-state automaton over a set of actions and states.
|
|
//
|
|
// This automaton is defined by:
|
|
// 1) a state space (explicit, always bits<32>).
|
|
// 2) a set of input symbols (actions, explicit) and
|
|
// 3) a transition function from state + action -> state.
|
|
//
|
|
// A theoretical automaton is defined by <Q, S, d, q0, F>:
|
|
// Q: A set of possible states.
|
|
// S: (sigma) The input alphabet.
|
|
// d: (delta) The transition function f(q in Q, s in S) -> q' in Q.
|
|
// F: The set of final (accepting) states.
|
|
//
|
|
// Because generating all possible states is tedious, we instead define the
|
|
// transition function only and crawl all reachable states starting from the
|
|
// initial state with all inputs under all transitions until termination.
|
|
//
|
|
// We define F = S, that is, all valid states are accepting.
|
|
//
|
|
// To ensure the generation of the automaton terminates, the state transitions
|
|
// are defined as a lattice (meaning every transitioned-to state is more
|
|
// specific than the transitioned-from state, for some definition of specificity).
|
|
// Concretely a transition may set one or more bits in the state that were
|
|
// previously zero to one. If any bit was not zero, the transition is invalid.
|
|
//
|
|
// Instead of defining all possible states (which would be cumbersome), the user
|
|
// provides a set of possible Transitions from state A, consuming an input
|
|
// symbol A to state B. The Transition object transforms state A to state B and
|
|
// acts as a predicate. This means the state space can be discovered by crawling
|
|
// all the possible transitions until none are valid.
|
|
//
|
|
// This automaton is considered to be nondeterministic, meaning that multiple
|
|
// transitions can occur from any (state, action) pair. The generated automaton
|
|
// is determinized, meaning that is executes in O(k) time where k is the input
|
|
// sequence length.
|
|
//
|
|
// In addition to a generated automaton that determines if a sequence of inputs
|
|
// is accepted or not, a table is emitted that allows determining a plausible
|
|
// sequence of states traversed to accept that input.
|
|
class GenericAutomaton {
|
|
// Name of a class that inherits from Transition. All records inheriting from
|
|
// this class will be considered when constructing the automaton.
|
|
string TransitionClass;
|
|
|
|
// Names of fields within TransitionClass that define the action symbol. This
|
|
// defines the action as an N-tuple.
|
|
//
|
|
// Each symbol field can be of class, int, string or code type.
|
|
// If the type of a field is a class, the Record's name is used verbatim
|
|
// in C++ and the class name is used as the C++ type name.
|
|
// If the type of a field is a string, code or int, that is also used
|
|
// verbatim in C++.
|
|
//
|
|
// To override the C++ type name for field F, define a field called TypeOf_F.
|
|
// This should be a string that will be used verbatim in C++.
|
|
//
|
|
// As an example, to define a 2-tuple with an enum and a string, one might:
|
|
// def MyTransition : Transition {
|
|
// MyEnum S1;
|
|
// int S2;
|
|
// }
|
|
// def MyAutomaton : GenericAutomaton }{
|
|
// let TransitionClass = "Transition";
|
|
// let SymbolFields = ["S1", "S2"];
|
|
// let TypeOf_S1 = "MyEnumInCxxKind";
|
|
// }
|
|
list<string> SymbolFields;
|
|
}
|
|
|
|
// All transitions inherit from Transition.
|
|
class Transition {
|
|
// A transition S' = T(S) is valid if, for every set bit in NewState, the
|
|
// corresponding bit in S is clear. That is:
|
|
// def T(S):
|
|
// S' = S | NewState
|
|
// return S' if S' != S else Failure
|
|
//
|
|
// The automaton generator uses this property to crawl the set of possible
|
|
// transitions from a starting state of 0b0.
|
|
bits<32> NewState;
|
|
}
|