CIRCT  20.0.0git
FSMGraph.cpp
Go to the documentation of this file.
1 //===- FSMGraph.cpp - 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 
10 
11 using namespace circt;
12 using namespace fsm;
13 
14 void FSMTransitionEdge::erase() {
15  // Update the prev node to point to the next node.
16  if (prevUse)
17  prevUse->nextUse = nextUse;
18  else
19  nextState->firstUse = nextUse;
20  // Update the next node to point to the prev node.
21  if (nextUse)
22  nextUse->prevUse = prevUse;
23  currentState->eraseTransitionEdge(this);
24 }
25 
26 void FSMStateNode::eraseTransitionEdge(FSMTransitionEdge *edge) {
27  edge->getTransition().erase();
28  transitions.erase(edge);
29 }
30 
31 FSMTransitionEdge *FSMStateNode::addTransitionEdge(FSMStateNode *nextState,
32  TransitionOp transition) {
33  auto *transitionEdge = new FSMTransitionEdge(this, transition, nextState);
34  nextState->recordUse(transitionEdge);
35  transitions.push_back(transitionEdge);
36  return transitionEdge;
37 }
38 
39 void FSMStateNode::recordUse(FSMTransitionEdge *transition) {
40  transition->nextUse = firstUse;
41  if (firstUse)
42  firstUse->prevUse = transition;
43  firstUse = transition;
44 }
45 
46 FSMGraph::FSMGraph(Operation *op) {
47  machine = dyn_cast<MachineOp>(op);
48  assert(machine && "Expected a fsm::MachineOp");
49 
50  // Find all states in the machine.
51  for (auto stateOp : machine.getOps<StateOp>()) {
52  // Add an edge to indicate that this state transitions to some other state.
53  auto *currentStateNode = getOrAddState(stateOp);
54 
55  for (auto transitionOp : stateOp.getTransitions().getOps<TransitionOp>()) {
56  auto *nextStateNode = getOrAddState(transitionOp.getNextStateOp());
57  currentStateNode->addTransitionEdge(nextStateNode, transitionOp);
58  }
59  }
60 }
61 
62 FSMStateNode *FSMGraph::lookup(StringAttr name) {
63  auto it = nodeMap.find(name);
64  if (it != nodeMap.end())
65  return it->second;
66  return nullptr;
67 }
68 
69 FSMStateNode *FSMGraph::lookup(StateOp state) {
70  return lookup(state.getNameAttr());
71 }
72 
73 FSMStateNode *FSMGraph::getOrAddState(StateOp state) {
74  // Try to insert an FSMStateNode. If its not inserted, it returns
75  // an iterator pointing to the node.
76  auto *&node = nodeMap[state.getNameAttr()];
77  if (!node) {
78  node = new FSMStateNode(state);
79  nodes.push_back(node);
80  }
81  return node;
82 }
83 
84 FSMStateNode *FSMGraph::createState(OpBuilder &builder, Location loc,
85  StringRef name) {
86  OpBuilder::InsertionGuard g(builder);
87  builder.setInsertionPointToEnd(&getMachine().getBody().front());
88  auto stateOp = builder.create<StateOp>(loc, name);
89  return getOrAddState(stateOp);
90 }
91 
92 FSMTransitionEdge *FSMGraph::createTransition(OpBuilder &builder, Location loc,
93  StateOp from, StateOp to) {
94  auto *currentStateNode = getOrAddState(from);
95  auto *nextStateNode = getOrAddState(to);
96  OpBuilder::InsertionGuard g(builder);
97  // Set the insertion point to the end of the transitions.
98  builder.setInsertionPointToEnd(&from.getTransitions().getBlocks().front());
99  auto transition = builder.create<TransitionOp>(loc, to);
100  return currentStateNode->addTransitionEdge(nextStateNode, transition);
101 }
102 
103 void FSMGraph::eraseState(StateOp state) {
104  auto *stateNode = getOrAddState(state);
105 
106  for (auto *incomingTransition : llvm::make_early_inc_range(stateNode->uses()))
107  incomingTransition->erase();
108 
109  for (auto *outgoingTransitions : llvm::make_early_inc_range(*stateNode))
110  outgoingTransitions->erase();
111  nodeMap.erase(state.getNameAttr());
112  nodes.erase(stateNode);
113 }
114 
115 void FSMGraph::renameState(StateOp state, StringRef name) {
116  auto *stateNode = getOrAddState(state);
117  auto nameStrAttr = StringAttr::get(state.getContext(), name);
118 
119  state.setName(nameStrAttr);
120 
121  // Update in- and outgoing transitions to the state.
122  auto updateTransitions = [&](auto &&transitionRange) {
123  for (auto *transition : transitionRange) {
124  auto transitionOp = transition->getTransition();
125  transitionOp->setAttr(transitionOp.getNextStateAttrName(), nameStrAttr);
126  }
127  };
128 
129  updateTransitions(stateNode->uses());
130  updateTransitions(*stateNode);
131 
132  // Update nodemap
133  nodeMap.erase(state.getNameAttr());
134  nodeMap[nameStrAttr] = stateNode;
135 }
assert(baseType &&"element must be base type")
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:55
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
Definition: fsm.py:1