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