14 #include "mlir/Pass/Pass.h"
19 #include "mlir/Support/IndentedOstream.h"
20 #include "llvm/ADT/ScopedHashTable.h"
21 #include "llvm/ADT/StringRef.h"
22 #include "llvm/Support/raw_ostream.h"
26 #define GEN_PASS_DEF_DCDOTPRINT
27 #include "circt/Dialect/DC/DCPasses.h.inc"
31 using namespace circt;
35 using ValueMap = llvm::ScopedHashTable<mlir::Value, std::string>;
68 std::string stringify(NodeType type) {
94 case NodeType::BranchOp:
96 case NodeType::BufferOp:
98 case NodeType::ForkOp:
100 case NodeType::FromESIOp:
102 case NodeType::JoinOp:
104 case NodeType::MergeOp:
106 case NodeType::PackOp:
108 case NodeType::SelectOp:
110 case NodeType::SinkOp:
112 case NodeType::SourceOp:
114 case NodeType::ToESIOp:
116 case NodeType::UnpackOp:
126 SmallVector<std::pair<mlir::Value, std::string>> incoming;
127 SmallVector<std::pair<mlir::Value, std::string>> outgoing;
132 static SmallVector<std::pair<mlir::Value, std::string>>
134 SmallVector<std::pair<mlir::Value, std::string>> ¤tMap,
136 SmallVector<std::pair<mlir::Value, std::string>> res;
137 for (
auto [i, v] : llvm::enumerate(values)) {
139 for (
const auto &[key, value] : currentMap) {
141 res.push_back({v, value});
146 std::string name =
"in_" + std::to_string(currentMap.size());
147 if (tokenFlag && i % 2 == 0)
148 name =
"token_" + std::to_string(currentMap.size());
149 res.push_back({v, name});
150 currentMap.push_back({v, name});
159 SmallVector<std::pair<mlir::Value, std::string>> &valuesMap) {
161 auto tokenFlag =
false;
162 if (isa<dc::UnpackOp>(op))
165 DotNode n = {NodeType::Null,
valueToName(op.getOperands(), valuesMap,
false),
166 valueToName(op.getOperands(), valuesMap, tokenFlag)};
168 TypeSwitch<mlir::Operation *>(&op)
169 .Case([&](dc::BranchOp) { n.nodeType = NodeType::BranchOp; })
170 .Case([&](dc::BufferOp) { n.nodeType = NodeType::BufferOp; })
171 .Case([&](dc::ForkOp) { n.nodeType = NodeType::ForkOp; })
172 .Case([&](dc::FromESIOp) { n.nodeType = NodeType::FromESIOp; })
173 .Case([&](dc::JoinOp) { n.nodeType = NodeType::JoinOp; })
174 .Case([&](dc::MergeOp) { n.nodeType = NodeType::MergeOp; })
175 .Case([&](dc::PackOp) { n.nodeType = NodeType::PackOp; })
176 .Case([&](dc::SelectOp) { n.nodeType = NodeType::SelectOp; })
177 .Case([&](dc::SinkOp) { n.nodeType = NodeType::SinkOp; })
178 .Case([&](dc::SourceOp) { n.nodeType = NodeType::SourceOp; })
179 .Case([&](dc::ToESIOp) { n.nodeType = NodeType::ToESIOp; })
180 .Case([&](dc::UnpackOp) { n.nodeType = NodeType::UnpackOp; });
188 SmallVector<std::pair<mlir::Value, std::string>> &valuesMap) {
190 DotNode n = {NodeType::Null,
valueToName(op.getOperands(), valuesMap,
false),
193 TypeSwitch<mlir::Operation *>(&op)
194 .Case([&](
comb::AddOp) { n.nodeType = NodeType::AddOp; })
195 .Case([&](
comb::AndOp) { n.nodeType = NodeType::AndOp; })
196 .Case([&](
comb::XorOp) { n.nodeType = NodeType::XorOp; })
197 .Case([&](
comb::OrOp) { n.nodeType = NodeType::OrOp; })
198 .Case([&](
comb::MulOp) { n.nodeType = NodeType::MulOp; })
199 .Case([&](
comb::MuxOp) { n.nodeType = NodeType::MuxOp; })
200 .Case<comb::ICmpOp>([&](
auto op) {
201 switch (op.getPredicate()) {
202 case circt::comb::ICmpPredicate::eq: {
203 n.nodeType = NodeType::EqOp;
206 case circt::comb::ICmpPredicate::ne: {
207 n.nodeType = NodeType::NeOp;
210 case circt::comb::ICmpPredicate::sgt: {
211 n.nodeType = NodeType::GtOp;
214 case circt::comb::ICmpPredicate::sge: {
215 n.nodeType = NodeType::GeOp;
218 case circt::comb::ICmpPredicate::slt: {
219 n.nodeType = NodeType::LtOp;
222 case circt::comb::ICmpPredicate::sle: {
223 n.nodeType = NodeType::LeOp;
226 case circt::comb::ICmpPredicate::ugt: {
227 n.nodeType = NodeType::GtOp;
230 case circt::comb::ICmpPredicate::uge: {
231 n.nodeType = NodeType::GeOp;
234 case circt::comb::ICmpPredicate::ult: {
235 n.nodeType = NodeType::LeOp;
238 case circt::comb::ICmpPredicate::ule: {
239 n.nodeType = NodeType::LtOp;
242 case circt::comb::ICmpPredicate::ceq: {
243 n.nodeType = NodeType::EqOp;
246 case circt::comb::ICmpPredicate::cne: {
247 n.nodeType = NodeType::NeOp;
250 case circt::comb::ICmpPredicate::weq: {
251 n.nodeType = NodeType::EqOp;
254 case circt::comb::ICmpPredicate::wne: {
255 n.nodeType = NodeType::NeOp;
265 struct DCDotPrintPass :
public circt::dc::impl::DCDotPrintBase<DCDotPrintPass> {
266 explicit DCDotPrintPass(raw_ostream &os) : os(os) {}
267 void runOnOperation()
override {
269 ModuleOp op = getOperation();
273 SmallVector<std::pair<mlir::Value, std::string>> valuesMap;
274 SmallVector<DotNode> nodes;
276 auto &moduleOps = op->getRegion(0).getBlocks();
277 for (
auto &moduleOp : moduleOps) {
279 for (
auto hmo : hwModuleOp) {
280 for (
auto &op : hmo->getRegion(0).getOps()) {
282 if (op.getDialect()->getNamespace() ==
"comb") {
285 nodes.push_back(node);
286 }
else if (op.getDialect()->getNamespace() ==
"dc") {
288 nodes.push_back(node);
295 for (
auto [i, n] : llvm::enumerate(nodes)) {
296 os << i <<
" [shape = polygon, label = \"" << stringify(n.nodeType)
299 for (
auto [
id, n] : llvm::enumerate(nodes)) {
300 if (n.nodeType == NodeType::UnpackOp)
301 for (
auto ic : n.incoming)
302 os <<
"token_" << ic.second <<
" -> " <<
id << R
"( [label = ")"
303 << ic.second << "\"]\n";
305 for (
auto [id1, n1] : llvm::enumerate(nodes)) {
306 for (
auto [id2, n2] : llvm::enumerate(nodes)) {
308 for (
const auto &n1Out : n1.outgoing) {
309 for (
const auto &[i, n2In] : llvm::enumerate(n2.incoming)) {
310 if (n1Out.first == n2In.first) {
311 os << id1 <<
" -> " << id2 <<
" [label = \"" << n1Out.second
319 for (
auto [
id, n] : llvm::enumerate(nodes)) {
320 if (n.nodeType == NodeType::PackOp)
321 for (
const auto &ic : n.outgoing)
322 os <<
id <<
" -> " << ic.second <<
" [label = \"" << ic.second
332 std::unique_ptr<mlir::OperationPass<mlir::ModuleOp>>
334 return std::make_unique<DCDotPrintPass>(llvm::errs());
static DotNode createDCNode(Operation &op, SmallVector< std::pair< mlir::Value, std::string >> &valuesMap)
creates node in the dataflow graph for DC operations
llvm::ScopedHashTable< mlir::Value, std::string > ValueMap
static DotNode createCombNode(Operation &op, SmallVector< std::pair< mlir::Value, std::string >> &valuesMap)
creates node in the dataflow graph for Comb operations
static SmallVector< std::pair< mlir::Value, std::string > > valueToName(const SmallVector< mlir::Value > &values, SmallVector< std::pair< mlir::Value, std::string >> ¤tMap, bool tokenFlag)
gives a unique name to each value in the graph
std::unique_ptr< mlir::OperationPass< mlir::ModuleOp > > createDCDotPrintPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.