CIRCT  19.0.0git
HWExportModuleHierarchy.cpp
Go to the documentation of this file.
1 //===- HWExportModuleHierarchy.cpp - Export Module Hierarchy ----*- 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 // Export the module and instance hierarchy information to JSON. This pass looks
9 // for modules with the firrtl.moduleHierarchyFile attribute and collects the
10 // hierarchy starting at those modules. The hierarchy information is then
11 // encoded as JSON in an sv.verbatim op with the output_file attribute set.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "PassDetail.h"
18 #include "circt/Dialect/HW/HWOps.h"
21 #include "circt/Support/Path.h"
22 #include "mlir/IR/Builders.h"
23 #include "mlir/Support/FileUtilities.h"
24 #include "llvm/Support/FileSystem.h"
25 #include "llvm/Support/JSON.h"
26 #include "llvm/Support/Path.h"
27 #include "llvm/Support/ToolOutputFile.h"
28 
29 using namespace circt;
30 
31 //===----------------------------------------------------------------------===//
32 // Pass Implementation
33 //===----------------------------------------------------------------------===//
34 
36  : public sv::HWExportModuleHierarchyBase<HWExportModuleHierarchyPass> {
37 
38 private:
39  DenseMap<Operation *, hw::InnerSymbolNamespace> moduleNamespaces;
40 
41  void printHierarchy(hw::InstanceOp &inst, SymbolTable &symbolTable,
42  llvm::json::OStream &j,
43  SmallVectorImpl<Attribute> &symbols, unsigned &id);
44 
45  void extractHierarchyFromTop(hw::HWModuleOp op, SymbolTable &symbolTable,
46  llvm::raw_ostream &os,
47  SmallVectorImpl<Attribute> &symbols);
48 
49  void runOnOperation() override;
50 };
51 
52 /// Recursively print the module hierarchy as serialized as JSON.
54  hw::InstanceOp &inst, SymbolTable &symbolTable, llvm::json::OStream &j,
55  SmallVectorImpl<Attribute> &symbols, unsigned &id) {
56  auto moduleOp = inst->getParentOfType<hw::HWModuleOp>();
57  auto innerSym = inst.getInnerSymAttr();
58  if (!innerSym) {
59  auto &ns = moduleNamespaces.try_emplace(moduleOp, moduleOp).first->second;
60  innerSym = hw::InnerSymAttr::get(
61  StringAttr::get(inst.getContext(), ns.newName(inst.getInstanceName())));
62  inst->setAttr("inner_sym", innerSym);
63  }
64 
65  j.object([&] {
66  j.attribute("instance_name", ("{{" + Twine(id++) + "}}").str());
67  symbols.push_back(hw::InnerRefAttr::get(moduleOp.getModuleNameAttr(),
68  innerSym.getSymName()));
69  j.attribute("module_name", ("{{" + Twine(id++) + "}}").str());
70  symbols.push_back(inst.getModuleNameAttr());
71  j.attributeArray("instances", [&] {
72  // Only recurse on module ops, not extern or generated ops, whose internal
73  // are opaque.
74  auto *nextModuleOp =
75  symbolTable.lookup(inst.getModuleNameAttr().getValue());
76  if (auto module = dyn_cast<hw::HWModuleOp>(nextModuleOp)) {
77  for (auto op : module.getOps<hw::InstanceOp>()) {
78  printHierarchy(op, symbolTable, j, symbols, id);
79  }
80  }
81  });
82  });
83 }
84 
85 /// Return the JSON-serialized module hierarchy for the given module as the top
86 /// of the hierarchy.
88  hw::HWModuleOp op, SymbolTable &symbolTable, llvm::raw_ostream &os,
89  SmallVectorImpl<Attribute> &symbols) {
90  llvm::json::OStream j(os, 2);
91 
92  // As a special case for top-level module, set instance name to module name,
93  // since the top-level module is not instantiated.
94  j.object([&] {
95  j.attribute("instance_name", "{{0}}");
96  j.attribute("module_name", "{{0}}");
97  symbols.push_back(FlatSymbolRefAttr::get(op.getNameAttr()));
98  j.attributeArray("instances", [&] {
99  unsigned id = 1;
100  for (auto op : op.getOps<hw::InstanceOp>())
101  printHierarchy(op, symbolTable, j, symbols, id);
102  });
103  });
104 }
105 
106 /// Find the modules corresponding to the firrtl mainModule and DesignUnderTest,
107 /// and if they exist, emit a verbatim op with the module hierarchy for each.
109  mlir::ModuleOp mlirModule = getOperation();
110  std::optional<SymbolTable *> symbolTable;
111 
112  for (auto op : mlirModule.getOps<hw::HWModuleOp>()) {
113  auto attr = op->getAttrOfType<ArrayAttr>("firrtl.moduleHierarchyFile");
114  if (!attr)
115  continue;
116  for (auto file : attr.getAsRange<hw::OutputFileAttr>()) {
117  if (!symbolTable)
118  symbolTable = &getAnalysis<SymbolTable>();
119 
120  std::string jsonBuffer;
121  llvm::raw_string_ostream os(jsonBuffer);
122  SmallVector<Attribute> symbols;
123 
124  extractHierarchyFromTop(op, **symbolTable, os, symbols);
125 
126  auto builder = ImplicitLocOpBuilder::atBlockEnd(
127  UnknownLoc::get(mlirModule.getContext()), mlirModule.getBody());
128  builder.create<emit::FileOp>(file.getFilename(), [&] {
129  builder.create<sv::VerbatimOp>(jsonBuffer, ValueRange{},
130  builder.getArrayAttr(symbols));
131  });
132  }
133  }
134 
135  markAllAnalysesPreserved();
136 }
137 
138 //===----------------------------------------------------------------------===//
139 // Pass Creation
140 //===----------------------------------------------------------------------===//
141 
142 std::unique_ptr<mlir::Pass> sv::createHWExportModuleHierarchyPass() {
143  return std::make_unique<HWExportModuleHierarchyPass>();
144 }
Builder builder
void printHierarchy(hw::InstanceOp &inst, SymbolTable &symbolTable, llvm::json::OStream &j, SmallVectorImpl< Attribute > &symbols, unsigned &id)
Recursively print the module hierarchy as serialized as JSON.
void runOnOperation() override
Find the modules corresponding to the firrtl mainModule and DesignUnderTest, and if they exist,...
void extractHierarchyFromTop(hw::HWModuleOp op, SymbolTable &symbolTable, llvm::raw_ostream &os, SmallVectorImpl< Attribute > &symbols)
Return the JSON-serialized module hierarchy for the given module as the top of the hierarchy.
DenseMap< Operation *, hw::InnerSymbolNamespace > moduleNamespaces
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:54
std::unique_ptr< mlir::Pass > createHWExportModuleHierarchyPass()
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
Definition: DebugAnalysis.h:21