CIRCT 24.0.0git
Loading...
Searching...
No Matches
FSMGraph.h
Go to the documentation of this file.
1//===- FSMGraph.h - FSM graph -----------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the FSMGraph.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef CIRCT_DIALECT_FSM_FSMGRAPH_H
14#define CIRCT_DIALECT_FSM_FSMGRAPH_H
15
17#include "circt/Support/LLVM.h"
18#include "llvm/ADT/GraphTraits.h"
19#include "llvm/ADT/STLExtras.h"
20#include "llvm/ADT/iterator.h"
21#include "llvm/Support/DOTGraphTraits.h"
22#include "llvm/Support/GraphWriter.h"
23
24#include <regex>
25
26namespace circt {
27namespace fsm {
28
29namespace detail {
30/// This just maps a iterator of references to an iterator of addresses.
31template <typename It>
33 : public llvm::mapped_iterator<It, typename It::pointer (*)(
34 typename It::reference)> {
35 // This using statement is to get around a bug in MSVC. Without it, it
36 // tries to look up "It" as a member type of the parent class.
37 using Iterator = It;
38 static typename Iterator::value_type *
39 addrOf(typename Iterator::value_type &v) noexcept {
40 return std::addressof(v);
41 }
42 /* implicit */ AddressIterator(Iterator iterator)
43 : llvm::mapped_iterator<It, typename Iterator::pointer (*)(
44 typename Iterator::reference)>(iterator,
45 addrOf) {}
46};
47
48// Escapes any occurance of (regex) characters 'c' in 'str'. If 'noEscape' is
49// set, does not prepend a '\' character to the replaced value.
50static void escape(std::string &str, const char *c, bool noEscape = false) {
51 std::string replacement = std::string(c);
52 if (!noEscape)
53 replacement = R"(\)" + replacement;
54 str = std::regex_replace(str, std::regex(c), replacement);
55}
56
57// Dumps a range of operations to a string in a format suitable for embedding
58// inside a .dot edge/node label.
59template <typename TOpRange>
60static std::string dotSafeDumpOps(TOpRange ops) {
61 std::string dump;
62 llvm::raw_string_ostream ss(dump);
63 llvm::interleave(
64 ops, ss, [&](mlir::Operation &op) { op.print(ss); }, "\\n");
65
66 // Ensure that special characters which may be present in the Op dumps are
67 // properly escaped.
68 escape(dump, R"(")");
69 escape(dump, R"(\{)", /*noEscape=*/true);
70 escape(dump, R"(\})", /*noEscape=*/true);
71 return dump;
72}
73
74// Dumps a range of operations to a string.
75template <typename TOpRange>
76static std::string dumpOps(TOpRange ops) {
77 std::string dump;
78 llvm::raw_string_ostream ss(dump);
79 llvm::interleave(
80 ops, ss, [&](mlir::Operation &op) { op.print(ss); }, "\n");
81
82 return dump;
83}
84
85} // namespace detail
86
87class FSMStateNode;
88
89/// This is an edge in the FSMGraph. This tracks a transition between two
90/// states.
92 : public llvm::ilist_node_with_parent<FSMTransitionEdge, FSMStateNode> {
93public:
94 /// Get the state where the transition originates from.
96
97 /// Get the module which the FSM-like is instantiating.
98 FSMStateNode *getNextState() const { return nextState; }
99
100 TransitionOp getTransition() const { return transition; }
101
102 /// Erase this transition, removing it from the source state and the target
103 /// state's use-list.
104 void erase();
105
106private:
107 friend class FSMGraphBase;
108 friend class FSMStateNode;
109
115
116 /// The state where this transition originates from.
118
119 /// The transition that this is tracking.
120 TransitionOp transition;
121
122 /// The next state of this transition.
124
125 /// Intrusive linked list for other uses.
128};
129
130/// This is a Node in the FSMGraph. Each node represents a state in the FSM.
131class FSMStateNode : public llvm::ilist_node<FSMStateNode> {
132 using FSMTransitionList = llvm::iplist<FSMTransitionEdge>;
133
134public:
135 FSMStateNode() : state(nullptr) {}
136
137 /// Get the state operation that this node is tracking.
138 StateOp getState() const { return state; }
139
140 /// Adds a new transition edge from this state to 'nextState'.
142 TransitionOp transition);
143
144 /// Erases a transition edge from this state. This also removes the underlying
145 /// TransitionOp.
147
148 /// Iterate outgoing FSM transitions of this state.
150 iterator begin() { return transitions.begin(); }
151 iterator end() { return transitions.end(); }
152
153 /// Iterator for state uses.
155 : public llvm::iterator_facade_base<
156 UseIterator, std::forward_iterator_tag, FSMTransitionEdge *> {
157 UseIterator() : current(nullptr) {}
160 using llvm::iterator_facade_base<UseIterator, std::forward_iterator_tag,
161 FSMTransitionEdge *>::operator++;
163 assert(current && "incrementing past end");
164 current = current->nextUse;
165 return *this;
166 }
167 bool operator==(const UseIterator &other) const {
168 return current == other.current;
169 }
170
171 private:
173 };
174
175 /// Iterate the instance records which instantiate this module.
176 UseIterator usesBegin() { return {this}; }
177 UseIterator usesEnd() { return {}; }
178 llvm::iterator_range<UseIterator> uses() {
179 return llvm::make_range(usesBegin(), usesEnd());
180 }
181
182private:
183 friend class FSMTransitionEdge;
184
186 FSMStateNode(const FSMStateNode &) = delete;
187
188 /// Record that a tramsition referenced this state.
189 void recordUse(FSMTransitionEdge *transition);
190
191 /// The state.
192 StateOp state;
193
194 /// List of outgoing transitions from this state.
196
197 /// List of transitions which reference this state.
199
200 /// Provide access to the constructor.
201 friend class FSMGraph;
202};
203
204/// Graph representing FSM machines, their states and transitions between these.
205class FSMGraph {
206 /// This is the list of FSMStateNodes in the graph.
207 using NodeList = llvm::iplist<FSMStateNode>;
208
209public:
210 /// Create a new graph of an FSM machine operation.
211 explicit FSMGraph(Operation *operation);
212
213 /// Look up a FSMStateNode for a state.
214 FSMStateNode *lookup(StateOp op);
215
216 /// Lookup a FSMStateNode by name.
217 FSMStateNode *lookup(StringAttr name);
218
219 /// Lookup a FSMStateNode for a state.
220 FSMStateNode *operator[](StateOp op) { return lookup(op); }
221
222 /// Get the node corresponding to the entry state of the FSM.
224
225 /// Return the FSM machine operation which this graph tracks.
226 MachineOp getMachine() const { return machine; }
227
228 /// Retrieves the state node for a 'state'. If the node does not yet exists, a
229 /// new state node is created.
230 FSMStateNode *getOrAddState(StateOp state);
231
232 /// Creates a new StateOp operation in this machine and updates the graph.
233 FSMStateNode *createState(OpBuilder &builder, Location loc, StringRef name);
234
235 /// Creates a new transition operation between two states and updates the
236 /// graph.
237 FSMTransitionEdge *createTransition(OpBuilder &builder, Location loc,
238 StateOp from, StateOp to);
239
240 /// Removes this state from the graph. This will also remove the state in the
241 /// underlying machine and all transitions to the state.
242 void eraseState(StateOp state);
243
244 /// Renames the 'state' to the provided 'name', and updates all referencing
245 /// transitions.
246 void renameState(StateOp state, StringRef name);
247
248 /// Iterate through all states.
250 iterator begin() { return nodes.begin(); }
251 iterator end() { return nodes.end(); }
252
253private:
254 FSMGraph(const FSMGraph &) = delete;
255
256 /// The node under which all states are nested.
257 MachineOp machine;
258
259 /// The storage for graph nodes, with deterministic iteration.
261
262 /// This maps each StateOp to its graph node.
263 llvm::DenseMap<Attribute, FSMStateNode *> nodeMap;
264};
265
266} // namespace fsm
267} // namespace circt
268
269// Provide graph traits for iterating the states.
270template <>
271struct llvm::GraphTraits<circt::fsm::FSMStateNode *> {
273 using NodeRef = NodeType *;
274
275 // Helper for getting the next state of a transition edge.
277 return transition->getNextState();
278 }
279
281 llvm::mapped_iterator<circt::fsm::FSMStateNode::iterator,
282 decltype(&getNextState)>;
283
284 static NodeRef getEntryNode(NodeRef node) { return node; }
285 // NOLINTNEXTLINE(readability-identifier-naming)
287 return {node->begin(), &getNextState};
288 }
289 // NOLINTNEXTLINE(readability-identifier-naming)
291 return {node->end(), &getNextState};
292 }
293};
294
295// Graph traits for the FSM graph.
296template <>
297struct llvm::GraphTraits<circt::fsm::FSMGraph *>
298 : public llvm::GraphTraits<circt::fsm::FSMStateNode *> {
300
302 return graph->getEntryNode();
303 }
304 // NOLINTNEXTLINE(readability-identifier-naming)
306 return graph->begin();
307 }
308 // NOLINTNEXTLINE(readability-identifier-naming)
310 return graph->end();
311 }
312};
313
314// Graph traits for DOT labelling.
315template <>
316struct llvm::DOTGraphTraits<circt::fsm::FSMGraph *>
317 : public llvm::DefaultDOTGraphTraits {
318 using DefaultDOTGraphTraits::DefaultDOTGraphTraits;
319
320 static std::string getNodeLabel(circt::fsm::FSMStateNode *node,
322 // The name of the graph node is the state name.
323 return node->getState().getSymName().str();
324 }
325
328 // The description of the node is the dump of its Output region.
329 return circt::fsm::detail::dumpOps(node->getState().getOutput().getOps());
330 }
331
332 template <typename Iterator>
333 static std::string getEdgeAttributes(const circt::fsm::FSMStateNode *node,
334 Iterator it, circt::fsm::FSMGraph *) {
335 // Set an edge label that is the dump of the inner contents of the guard of
336 // the transition.
337 circt::fsm::FSMTransitionEdge *edge = *it.getCurrent();
338 circt::fsm::TransitionOp transition = edge->getTransition();
339 if (!transition.hasGuard())
340 return "";
341
342 std::string attrs = "label=\"";
343 attrs += circt::fsm::detail::dotSafeDumpOps(llvm::make_filter_range(
344 transition.getGuard().getOps(), [](mlir::Operation &op) {
345 // Ignore implicit fsm.return/fsm.output operations with no operands.
346 if (isa<circt::fsm::ReturnOp, circt::fsm::OutputOp>(op))
347 return op.getNumOperands() != 0;
348
349 return true;
350 }));
351 attrs += "\"";
352 return attrs;
353 }
354
356 GraphWriter<circt::fsm::FSMGraph *> &gw) {
357 // Print a separate node for global variables in the FSM.
358 llvm::raw_ostream &os = gw.getOStream();
359
360 os << "variables [shape=record,label=\"Variables|";
361 os << circt::fsm::detail::dotSafeDumpOps(llvm::make_filter_range(
362 graph->getMachine().getOps(), [](mlir::Operation &op) {
363 // Filter state ops; these are printed as separate nodes in the graph.
364 return !isa<circt::fsm::StateOp>(&op);
365 }));
366 os << "\"]";
367 }
368};
369
370#endif // CIRCT_DIALECT_FSM_FSMGRAPH_H
assert(baseType &&"element must be base type")
static void dump(DIModule &module, raw_indented_ostream &os)
NamedAttrList attrs
Graph representing FSM machines, their states and transitions between these.
Definition FSMGraph.h:205
FSMStateNode * createState(OpBuilder &builder, Location loc, StringRef name)
Creates a new StateOp operation in this machine and updates the graph.
Definition FSMGraph.cpp:84
FSMTransitionEdge * createTransition(OpBuilder &builder, Location loc, StateOp from, StateOp to)
Creates a new transition operation between two states and updates the graph.
Definition FSMGraph.cpp:92
NodeList nodes
The storage for graph nodes, with deterministic iteration.
Definition FSMGraph.h:260
FSMStateNode * lookup(StateOp op)
Look up a FSMStateNode for a state.
FSMStateNode * operator[](StateOp op)
Lookup a FSMStateNode for a state.
Definition FSMGraph.h:220
MachineOp getMachine() const
Return the FSM machine operation which this graph tracks.
Definition FSMGraph.h:226
void eraseState(StateOp state)
Removes this state from the graph.
Definition FSMGraph.cpp:103
MachineOp machine
The node under which all states are nested.
Definition FSMGraph.h:257
llvm::DenseMap< Attribute, FSMStateNode * > nodeMap
This maps each StateOp to its graph node.
Definition FSMGraph.h:263
void renameState(StateOp state, StringRef name)
Renames the 'state' to the provided 'name', and updates all referencing transitions.
Definition FSMGraph.cpp:115
detail::AddressIterator< NodeList::iterator > iterator
Iterate through all states.
Definition FSMGraph.h:249
FSMStateNode * getEntryNode()
Get the node corresponding to the entry state of the FSM.
FSMGraph(const FSMGraph &)=delete
llvm::iplist< FSMStateNode > NodeList
This is the list of FSMStateNodes in the graph.
Definition FSMGraph.h:207
FSMGraph(Operation *operation)
Create a new graph of an FSM machine operation.
FSMStateNode * getOrAddState(StateOp state)
Retrieves the state node for a 'state'.
Definition FSMGraph.cpp:73
This is a Node in the FSMGraph. Each node represents a state in the FSM.
Definition FSMGraph.h:131
llvm::iplist< FSMTransitionEdge > FSMTransitionList
Definition FSMGraph.h:132
FSMStateNode(const FSMStateNode &)=delete
FSMStateNode(StateOp state)
Definition FSMGraph.h:185
friend class FSMTransitionEdge
Definition FSMGraph.h:183
UseIterator usesBegin()
Iterate the instance records which instantiate this module.
Definition FSMGraph.h:176
FSMTransitionList transitions
List of outgoing transitions from this state.
Definition FSMGraph.h:195
StateOp state
The state.
Definition FSMGraph.h:192
StateOp getState() const
Get the state operation that this node is tracking.
Definition FSMGraph.h:138
FSMTransitionEdge * firstUse
List of transitions which reference this state.
Definition FSMGraph.h:198
void recordUse(FSMTransitionEdge *transition)
Record that a tramsition referenced this state.
Definition FSMGraph.cpp:39
void eraseTransitionEdge(FSMTransitionEdge *edge)
Erases a transition edge from this state.
Definition FSMGraph.cpp:26
UseIterator usesEnd()
Definition FSMGraph.h:177
friend class FSMGraph
Provide access to the constructor.
Definition FSMGraph.h:201
detail::AddressIterator< FSMTransitionList::iterator > iterator
Iterate outgoing FSM transitions of this state.
Definition FSMGraph.h:149
llvm::iterator_range< UseIterator > uses()
Definition FSMGraph.h:178
FSMTransitionEdge * addTransitionEdge(FSMStateNode *nextState, TransitionOp transition)
Adds a new transition edge from this state to 'nextState'.
Definition FSMGraph.cpp:31
This is an edge in the FSMGraph.
Definition FSMGraph.h:92
FSMStateNode * currentState
The state where this transition originates from.
Definition FSMGraph.h:117
TransitionOp getTransition() const
Definition FSMGraph.h:100
FSMStateNode * getNextState() const
Get the module which the FSM-like is instantiating.
Definition FSMGraph.h:98
FSMStateNode * getCurrentState() const
Get the state where the transition originates from.
Definition FSMGraph.h:95
TransitionOp transition
The transition that this is tracking.
Definition FSMGraph.h:120
FSMTransitionEdge(const FSMTransitionEdge &)=delete
void erase()
Erase this transition, removing it from the source state and the target state's use-list.
Definition FSMGraph.cpp:14
FSMTransitionEdge * prevUse
Definition FSMGraph.h:127
FSMStateNode * nextState
The next state of this transition.
Definition FSMGraph.h:123
FSMTransitionEdge(FSMStateNode *currentState, TransitionOp transition, FSMStateNode *nextState)
Definition FSMGraph.h:110
FSMTransitionEdge * nextUse
Intrusive linked list for other uses.
Definition FSMGraph.h:126
static std::string dotSafeDumpOps(TOpRange ops)
Definition FSMGraph.h:60
static void escape(std::string &str, const char *c, bool noEscape=false)
Definition FSMGraph.h:50
static std::string dumpOps(TOpRange ops)
Definition FSMGraph.h:76
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition fsm.py:1
Iterator for state uses.
Definition FSMGraph.h:156
FSMTransitionEdge * operator*() const
Definition FSMGraph.h:159
bool operator==(const UseIterator &other) const
Definition FSMGraph.h:167
This just maps a iterator of references to an iterator of addresses.
Definition FSMGraph.h:34
AddressIterator(Iterator iterator)
Definition FSMGraph.h:42
static Iterator::value_type * addrOf(typename Iterator::value_type &v) noexcept
Definition FSMGraph.h:39
static std::string getNodeDescription(circt::fsm::FSMStateNode *node, circt::fsm::FSMGraph *)
Definition FSMGraph.h:326
static void addCustomGraphFeatures(const circt::fsm::FSMGraph *graph, GraphWriter< circt::fsm::FSMGraph * > &gw)
Definition FSMGraph.h:355
static std::string getEdgeAttributes(const circt::fsm::FSMStateNode *node, Iterator it, circt::fsm::FSMGraph *)
Definition FSMGraph.h:333
static std::string getNodeLabel(circt::fsm::FSMStateNode *node, circt::fsm::FSMGraph *)
Definition FSMGraph.h:320
static nodes_iterator nodes_end(circt::fsm::FSMGraph *graph)
Definition FSMGraph.h:309
static NodeRef getEntryNode(circt::fsm::FSMGraph *graph)
Definition FSMGraph.h:301
circt::fsm::FSMGraph::iterator nodes_iterator
Definition FSMGraph.h:299
static nodes_iterator nodes_begin(circt::fsm::FSMGraph *graph)
Definition FSMGraph.h:305
static ChildIteratorType child_end(NodeRef node)
Definition FSMGraph.h:290
llvm::mapped_iterator< circt::fsm::FSMStateNode::iterator, decltype(&getNextState)> ChildIteratorType
Definition FSMGraph.h:280
static NodeRef getNextState(const circt::fsm::FSMTransitionEdge *transition)
Definition FSMGraph.h:276
static ChildIteratorType child_begin(NodeRef node)
Definition FSMGraph.h:286
static NodeRef getEntryNode(NodeRef node)
Definition FSMGraph.h:284