13 #ifndef CIRCT_DIALECT_FSM_FSMGRAPH_H
14 #define CIRCT_DIALECT_FSM_FSMGRAPH_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"
31 template <
typename It>
32 struct AddressIterator
33 :
public llvm::mapped_iterator<It, typename It::pointer (*)(
34 typename It::reference)> {
38 static typename Iterator::value_type *
39 addrOf(
typename Iterator::value_type &v) noexcept {
40 return std::addressof(v);
42 AddressIterator(Iterator iterator)
43 :
llvm::mapped_iterator<It, typename Iterator::pointer (*)(
44 typename Iterator::reference)>(iterator,
50 static void escape(std::string &str,
const char *c,
bool noEscape =
false) {
51 std::string replacement = std::string(c);
53 replacement = R
"(\)" + replacement;
54 str = std::regex_replace(str, std::regex(c), replacement);
59 template <
typename TOpRange>
60 static std::string dotSafeDumpOps(TOpRange ops) {
62 llvm::raw_string_ostream ss(
dump);
64 ops, ss, [&](mlir::Operation &op) { op.print(ss); },
"\\n");
69 escape(dump, R"(\{)", true);
70 escape(
dump, R
"(\})", true);
75 template <
typename TOpRange>
76 static std::string dumpOps(TOpRange ops) {
78 llvm::raw_string_ostream ss(
dump);
80 ops, ss, [&](mlir::Operation &op) { op.print(ss); },
"\n");
91 class FSMTransitionEdge
92 :
public llvm::ilist_node_with_parent<FSMTransitionEdge, FSMStateNode> {
95 FSMStateNode *getCurrentState()
const {
return currentState; }
98 FSMStateNode *getNextState()
const {
return nextState; }
100 TransitionOp getTransition()
const {
return transition; }
107 friend class FSMGraphBase;
108 friend class FSMStateNode;
110 FSMTransitionEdge(FSMStateNode *currentState, TransitionOp transition,
111 FSMStateNode *nextState)
112 : currentState(currentState), transition(transition),
113 nextState(nextState) {}
114 FSMTransitionEdge(
const FSMTransitionEdge &) =
delete;
117 FSMStateNode *currentState;
120 TransitionOp transition;
123 FSMStateNode *nextState;
126 FSMTransitionEdge *nextUse =
nullptr;
127 FSMTransitionEdge *prevUse =
nullptr;
131 class FSMStateNode :
public llvm::ilist_node<FSMStateNode> {
132 using FSMTransitionList = llvm::iplist<FSMTransitionEdge>;
135 FSMStateNode() : state(nullptr) {}
138 StateOp getState()
const {
return state; }
141 FSMTransitionEdge *addTransitionEdge(FSMStateNode *nextState,
142 TransitionOp transition);
146 void eraseTransitionEdge(FSMTransitionEdge *edge);
149 using iterator = detail::AddressIterator<FSMTransitionList::iterator>;
150 iterator begin() {
return transitions.begin(); }
151 iterator
end() {
return transitions.end(); }
155 :
public llvm::iterator_facade_base<
156 UseIterator, std::forward_iterator_tag, FSMTransitionEdge *> {
157 UseIterator() : current(nullptr) {}
158 UseIterator(FSMStateNode *node) : current(node->firstUse) {}
159 FSMTransitionEdge *
operator*()
const {
return current; }
160 using llvm::iterator_facade_base<UseIterator, std::forward_iterator_tag,
161 FSMTransitionEdge *>::operator++;
162 UseIterator &operator++() {
163 assert(current &&
"incrementing past end");
164 current = current->nextUse;
167 bool operator==(
const UseIterator &other)
const {
168 return current == other.current;
172 FSMTransitionEdge *current;
176 UseIterator usesBegin() {
return {
this}; }
177 UseIterator usesEnd() {
return {}; }
178 llvm::iterator_range<UseIterator> uses() {
179 return llvm::make_range(usesBegin(), usesEnd());
183 friend class FSMTransitionEdge;
185 FSMStateNode(StateOp state) : state(state) {}
186 FSMStateNode(
const FSMStateNode &) =
delete;
189 void recordUse(FSMTransitionEdge *transition);
195 FSMTransitionList transitions;
198 FSMTransitionEdge *firstUse =
nullptr;
201 friend class FSMGraph;
207 using NodeList = llvm::iplist<FSMStateNode>;
211 explicit FSMGraph(Operation *operation);
214 FSMStateNode *lookup(StateOp op);
217 FSMStateNode *lookup(StringAttr name);
220 FSMStateNode *operator[](StateOp op) {
return lookup(op); }
223 FSMStateNode *getEntryNode();
226 MachineOp getMachine()
const {
return machine; }
230 FSMStateNode *getOrAddState(StateOp state);
233 FSMStateNode *createState(OpBuilder &builder, Location loc, StringRef name);
237 FSMTransitionEdge *createTransition(OpBuilder &builder, Location loc,
238 StateOp from, StateOp to);
242 void eraseState(StateOp state);
246 void renameState(StateOp state, StringRef name);
249 using iterator = detail::AddressIterator<NodeList::iterator>;
250 iterator begin() {
return nodes.begin(); }
251 iterator
end() {
return nodes.end(); }
254 FSMGraph(
const FSMGraph &) =
delete;
263 llvm::DenseMap<Attribute, FSMStateNode *> nodeMap;
271 struct llvm::GraphTraits<
circt::fsm::FSMStateNode *> {
272 using NodeType = circt::fsm::FSMStateNode;
273 using NodeRef = NodeType *;
276 static NodeRef getNextState(
const circt::fsm::FSMTransitionEdge *transition) {
277 return transition->getNextState();
280 using ChildIteratorType =
281 llvm::mapped_iterator<circt::fsm::FSMStateNode::iterator,
282 decltype(&getNextState)>;
284 static NodeRef getEntryNode(NodeRef node) {
return node; }
286 static ChildIteratorType child_begin(NodeRef node) {
287 return {node->begin(), &getNextState};
290 static ChildIteratorType child_end(NodeRef node) {
291 return {node->end(), &getNextState};
297 struct llvm::GraphTraits<
circt::fsm::FSMGraph *>
298 :
public llvm::GraphTraits<circt::fsm::FSMStateNode *> {
299 using nodes_iterator = circt::fsm::FSMGraph::iterator;
301 static NodeRef getEntryNode(circt::fsm::FSMGraph *graph) {
302 return graph->getEntryNode();
305 static nodes_iterator nodes_begin(circt::fsm::FSMGraph *graph) {
306 return graph->begin();
309 static nodes_iterator nodes_end(circt::fsm::FSMGraph *graph) {
316 struct llvm::DOTGraphTraits<
circt::fsm::FSMGraph *>
317 :
public llvm::DefaultDOTGraphTraits {
318 using DefaultDOTGraphTraits::DefaultDOTGraphTraits;
320 static std::string getNodeLabel(circt::fsm::FSMStateNode *node,
321 circt::fsm::FSMGraph *) {
323 return node->getState().getSymName().str();
326 static std::string getNodeDescription(circt::fsm::FSMStateNode *node,
327 circt::fsm::FSMGraph *) {
329 return circt::fsm::detail::dumpOps(node->getState().getOutput().getOps());
332 template <
typename Iterator>
333 static std::string getEdgeAttributes(
const circt::fsm::FSMStateNode *node,
334 Iterator it, circt::fsm::FSMGraph *) {
337 circt::fsm::FSMTransitionEdge *edge = *it.getCurrent();
338 circt::fsm::TransitionOp transition = edge->getTransition();
339 if (!transition.hasGuard())
342 std::string attrs =
"label=\"";
343 attrs += circt::fsm::detail::dotSafeDumpOps(llvm::make_filter_range(
344 transition.getGuard().getOps(), [](mlir::Operation &op) {
346 if (isa<circt::fsm::ReturnOp, circt::fsm::OutputOp>(op))
347 return op.getNumOperands() != 0;
355 static void addCustomGraphFeatures(
const circt::fsm::FSMGraph *graph,
356 GraphWriter<circt::fsm::FSMGraph *> &gw) {
358 llvm::raw_ostream &os = gw.getOStream();
360 os <<
"variables [shape=record,label=\"Variables|";
361 os << circt::fsm::detail::dotSafeDumpOps(llvm::make_filter_range(
362 graph->getMachine().getOps(), [](mlir::Operation &op) {
364 return !isa<circt::fsm::StateOp>(&op);
assert(baseType &&"element must be base type")
static void dump(DIModule &module, raw_indented_ostream &os)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
FVInt operator*(uint64_t a, const FVInt &b)
bool operator==(uint64_t a, const FVInt &b)