CIRCT  20.0.0git
HWModuleGraph.h
Go to the documentation of this file.
1 //===- HWModuleGraph.h - HWModule 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 HWModuleGraph.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef CIRCT_DIALECT_HW_HWMODULEGRAPH_H
14 #define CIRCT_DIALECT_HW_HWMODULEGRAPH_H
15 
18 #include "circt/Dialect/HW/HWOps.h"
20 #include "circt/Support/LLVM.h"
21 #include "llvm/ADT/GraphTraits.h"
22 #include "llvm/ADT/STLExtras.h"
23 #include "llvm/ADT/TypeSwitch.h"
24 #include "llvm/ADT/iterator.h"
25 #include "llvm/Support/DOTGraphTraits.h"
26 #include "llvm/Support/GraphWriter.h"
27 
28 namespace circt {
29 namespace hw {
30 namespace detail {
31 
32 // Using declaration to avoid polluting global namespace with CIRCT-specific
33 // graph traits for mlir::Operation.
34 using HWOperation = mlir::Operation;
35 
36 } // namespace detail
37 } // namespace hw
38 } // namespace circt
39 
40 template <>
41 struct llvm::GraphTraits<circt::hw::detail::HWOperation *> {
43  using NodeRef = NodeType *;
44 
45  using ChildIteratorType = mlir::Operation::user_iterator;
46  static NodeRef getEntryNode(NodeRef op) { return op; }
47  static ChildIteratorType child_begin(NodeRef op) { return op->user_begin(); }
48  static ChildIteratorType child_end(NodeRef op) { return op->user_end(); }
49 };
50 
51 template <>
52 struct llvm::GraphTraits<circt::hw::HWModuleOp>
53  : public llvm::GraphTraits<circt::hw::detail::HWOperation *> {
54  using GraphType = circt::hw::HWModuleOp;
55 
57  return &mod.getBodyBlock()->front();
58  }
59 
60  using nodes_iterator = pointer_iterator<mlir::Block::iterator>;
62  return nodes_iterator{mod.getBodyBlock()->begin()};
63  }
65  return nodes_iterator{mod.getBodyBlock()->end()};
66  }
67 };
68 
69 template <>
70 struct llvm::DOTGraphTraits<circt::hw::HWModuleOp>
71  : public llvm::DefaultDOTGraphTraits {
72  using DefaultDOTGraphTraits::DefaultDOTGraphTraits;
73 
74  static std::string getNodeLabel(circt::hw::detail::HWOperation *node,
75  circt::hw::HWModuleOp) {
76  return llvm::TypeSwitch<mlir::Operation *, std::string>(node)
77  .Case<circt::comb::AddOp>([&](auto) { return "+"; })
78  .Case<circt::comb::SubOp>([&](auto) { return "-"; })
79  .Case<circt::comb::AndOp>([&](auto) { return "&"; })
80  .Case<circt::comb::OrOp>([&](auto) { return "|"; })
81  .Case<circt::comb::XorOp>([&](auto) { return "^"; })
82  .Case<circt::comb::MulOp>([&](auto) { return "*"; })
83  .Case<circt::comb::MuxOp>([&](auto) { return "mux"; })
84  .Case<circt::comb::ShrSOp, circt::comb::ShrUOp>(
85  [&](auto) { return ">>"; })
86  .Case<circt::comb::ShlOp>([&](auto) { return "<<"; })
87  .Case<circt::comb::ICmpOp>([&](auto op) {
88  switch (op.getPredicate()) {
89  case circt::comb::ICmpPredicate::eq:
90  case circt::comb::ICmpPredicate::ceq:
91  case circt::comb::ICmpPredicate::weq:
92  return "==";
93  case circt::comb::ICmpPredicate::wne:
94  case circt::comb::ICmpPredicate::cne:
95  case circt::comb::ICmpPredicate::ne:
96  return "!=";
97  case circt::comb::ICmpPredicate::uge:
98  case circt::comb::ICmpPredicate::sge:
99  return ">=";
100  case circt::comb::ICmpPredicate::ugt:
101  case circt::comb::ICmpPredicate::sgt:
102  return ">";
103  case circt::comb::ICmpPredicate::ule:
104  case circt::comb::ICmpPredicate::sle:
105  return "<=";
106  case circt::comb::ICmpPredicate::ult:
107  case circt::comb::ICmpPredicate::slt:
108  return "<";
109  }
110  llvm_unreachable("unhandled ICmp predicate");
111  })
112  .Case<circt::seq::FirRegOp>([&](auto op) { return op.getName().str(); })
113  .Case<circt::seq::CompRegOp>([&](auto op) -> std::string {
114  if (auto name = op.getName())
115  return name->str();
116  return "reg";
117  })
118  .Case<circt::hw::ConstantOp>([&](auto op) {
119  llvm::SmallString<64> valueString;
120  op.getValue().toString(valueString, 10, false);
121  return valueString.str().str();
122  })
123  .Default([&](auto op) { return op->getName().getStringRef().str(); });
124  }
125 
127  circt::hw::HWModuleOp) {
128  return llvm::TypeSwitch<mlir::Operation *, std::string>(node)
129  .Case<circt::hw::ConstantOp>(
130  [&](auto) { return "fillcolor=darkgoldenrod1,style=filled"; })
131  .Case<circt::comb::MuxOp>([&](auto) {
132  return "shape=invtrapezium,fillcolor=bisque,style=filled";
133  })
134  .Case<circt::hw::OutputOp>(
135  [&](auto) { return "fillcolor=lightblue,style=filled"; })
136  .Default([&](auto op) {
137  return llvm::TypeSwitch<mlir::Dialect *, std::string>(
138  op->getDialect())
139  .Case<circt::comb::CombDialect>([&](auto) {
140  return "shape=oval,fillcolor=bisque,style=filled";
141  })
142  .template Case<circt::seq::SeqDialect>([&](auto) {
143  return "shape=folder,fillcolor=gainsboro,style=filled";
144  })
145  .Default([&](auto) { return ""; });
146  });
147  }
148 
149  static void
150  addCustomGraphFeatures(circt::hw::HWModuleOp mod,
151  llvm::GraphWriter<circt::hw::HWModuleOp> &g) {
152 
153  // Add module input args.
154  auto &os = g.getOStream();
155  os << "subgraph cluster_entry_args {\n";
156  os << "label=\"Input arguments\";\n";
157  circt::hw::ModulePortInfo iports(mod.getPortList());
158  for (auto [info, arg] :
159  llvm::zip(iports.getInputs(), mod.getBodyBlock()->getArguments())) {
160  g.emitSimpleNode(reinterpret_cast<void *>(&arg), "",
161  info.getName().str());
162  }
163  os << "}\n";
164  for (auto [info, arg] :
165  llvm::zip(iports.getInputs(), mod.getBodyBlock()->getArguments())) {
166  for (auto *user : arg.getUsers()) {
167  g.emitEdge(reinterpret_cast<void *>(&arg), 0, user, -1, "");
168  }
169  }
170  }
171 
172  template <typename Iterator>
174  Iterator it, circt::hw::HWModuleOp mod) {
175 
176  mlir::OpOperand &operand = *it.getCurrent();
177  mlir::Value v = operand.get();
178  std::string str;
179  llvm::raw_string_ostream os(str);
180  auto verboseEdges = mod->getAttrOfType<mlir::BoolAttr>("dot_verboseEdges");
181  if (verboseEdges.getValue()) {
182  os << "label=\"" << operand.getOperandNumber() << " (" << v.getType()
183  << ")\"";
184  }
185 
186  int64_t width = circt::hw::getBitWidth(v.getType());
187  if (width > 1)
188  os << " style=bold";
189 
190  return os.str();
191  }
192 };
193 
194 #endif // CIRCT_DIALECT_HW_HWMODULEGRAPH_H
mlir::Operation HWOperation
Definition: HWModuleGraph.h:34
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
Definition: HWTypes.cpp:110
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
Definition: hw.py:1
This holds a decoded list of input/inout and output ports for a module or instance.
PortDirectionRange getInputs()
static void addCustomGraphFeatures(circt::hw::HWModuleOp mod, llvm::GraphWriter< circt::hw::HWModuleOp > &g)
static std::string getEdgeAttributes(circt::hw::detail::HWOperation *node, Iterator it, circt::hw::HWModuleOp mod)
static std::string getNodeLabel(circt::hw::detail::HWOperation *node, circt::hw::HWModuleOp)
Definition: HWModuleGraph.h:74
std::string getNodeAttributes(circt::hw::detail::HWOperation *node, circt::hw::HWModuleOp)
pointer_iterator< mlir::Block::iterator > nodes_iterator
Definition: HWModuleGraph.h:60
static nodes_iterator nodes_begin(GraphType mod)
Definition: HWModuleGraph.h:61
static nodes_iterator nodes_end(GraphType mod)
Definition: HWModuleGraph.h:64
static NodeRef getEntryNode(GraphType mod)
Definition: HWModuleGraph.h:56
static ChildIteratorType child_begin(NodeRef op)
Definition: HWModuleGraph.h:47
static ChildIteratorType child_end(NodeRef op)
Definition: HWModuleGraph.h:48
mlir::Operation::user_iterator ChildIteratorType
Definition: HWModuleGraph.h:45