forked from llvm/circt
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHWExportModuleHierarchy.cpp
More file actions
145 lines (127 loc) · 5.56 KB
/
HWExportModuleHierarchy.cpp
File metadata and controls
145 lines (127 loc) · 5.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//===- HWExportModuleHierarchy.cpp - Export Module Hierarchy ----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//===----------------------------------------------------------------------===//
//
// Export the module and instance hierarchy information to JSON. This pass looks
// for modules with the firrtl.moduleHierarchyFile attribute and collects the
// hierarchy starting at those modules. The hierarchy information is then
// encoded as JSON in an sv.verbatim op with the output_file attribute set.
//
//===----------------------------------------------------------------------===//
#include "circt/Dialect/Emit/EmitOps.h"
#include "circt/Dialect/HW/HWAttributes.h"
#include "circt/Dialect/HW/HWOps.h"
#include "circt/Dialect/HW/InnerSymbolNamespace.h"
#include "circt/Dialect/SV/SVOps.h"
#include "circt/Dialect/SV/SVPasses.h"
#include "circt/Support/Path.h"
#include "mlir/IR/Builders.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Support/FileUtilities.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/JSON.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ToolOutputFile.h"
namespace circt {
namespace sv {
#define GEN_PASS_DEF_HWEXPORTMODULEHIERARCHY
#include "circt/Dialect/SV/SVPasses.h.inc"
} // namespace sv
} // namespace circt
using namespace circt;
//===----------------------------------------------------------------------===//
// Pass Implementation
//===----------------------------------------------------------------------===//
class HWExportModuleHierarchyPass
: public circt::sv::impl::HWExportModuleHierarchyBase<
HWExportModuleHierarchyPass> {
private:
DenseMap<Operation *, hw::InnerSymbolNamespace> moduleNamespaces;
void printHierarchy(hw::InstanceOp &inst, SymbolTable &symbolTable,
llvm::json::OStream &j,
SmallVectorImpl<Attribute> &symbols, unsigned &id);
void extractHierarchyFromTop(hw::HWModuleOp op, SymbolTable &symbolTable,
llvm::raw_ostream &os,
SmallVectorImpl<Attribute> &symbols);
void runOnOperation() override;
};
/// Recursively print the module hierarchy as serialized as JSON.
void HWExportModuleHierarchyPass::printHierarchy(
hw::InstanceOp &inst, SymbolTable &symbolTable, llvm::json::OStream &j,
SmallVectorImpl<Attribute> &symbols, unsigned &id) {
auto moduleOp = inst->getParentOfType<hw::HWModuleOp>();
auto innerSym = inst.getInnerSymAttr();
if (!innerSym) {
auto &ns = moduleNamespaces.try_emplace(moduleOp, moduleOp).first->second;
innerSym = hw::InnerSymAttr::get(
StringAttr::get(inst.getContext(), ns.newName(inst.getInstanceName())));
inst->setAttr("inner_sym", innerSym);
}
j.object([&] {
j.attribute("instance_name", ("{{" + Twine(id++) + "}}").str());
symbols.push_back(hw::InnerRefAttr::get(moduleOp.getModuleNameAttr(),
innerSym.getSymName()));
j.attribute("module_name", ("{{" + Twine(id++) + "}}").str());
symbols.push_back(inst.getModuleNameAttr());
j.attributeArray("instances", [&] {
// Only recurse on module ops, not extern or generated ops, whose internal
// are opaque.
auto *nextModuleOp =
symbolTable.lookup(inst.getModuleNameAttr().getValue());
if (auto module = dyn_cast<hw::HWModuleOp>(nextModuleOp)) {
for (auto op : module.getOps<hw::InstanceOp>()) {
if (!op.getDoNotPrint())
printHierarchy(op, symbolTable, j, symbols, id);
}
}
});
});
}
/// Return the JSON-serialized module hierarchy for the given module as the top
/// of the hierarchy.
void HWExportModuleHierarchyPass::extractHierarchyFromTop(
hw::HWModuleOp op, SymbolTable &symbolTable, llvm::raw_ostream &os,
SmallVectorImpl<Attribute> &symbols) {
llvm::json::OStream j(os, 2);
// As a special case for top-level module, set instance name to module name,
// since the top-level module is not instantiated.
j.object([&] {
j.attribute("instance_name", "{{0}}");
j.attribute("module_name", "{{0}}");
symbols.push_back(FlatSymbolRefAttr::get(op.getNameAttr()));
j.attributeArray("instances", [&] {
unsigned id = 1;
for (auto op : op.getOps<hw::InstanceOp>())
printHierarchy(op, symbolTable, j, symbols, id);
});
});
}
/// Find the modules corresponding to the firrtl mainModule and DesignUnderTest,
/// and if they exist, emit a verbatim op with the module hierarchy for each.
void HWExportModuleHierarchyPass::runOnOperation() {
mlir::ModuleOp mlirModule = getOperation();
std::optional<SymbolTable *> symbolTable;
for (auto op : mlirModule.getOps<hw::HWModuleOp>()) {
auto attr = op->getAttrOfType<ArrayAttr>("firrtl.moduleHierarchyFile");
if (!attr)
continue;
for (auto file : attr.getAsRange<hw::OutputFileAttr>()) {
if (!symbolTable)
symbolTable = &getAnalysis<SymbolTable>();
std::string jsonBuffer;
llvm::raw_string_ostream os(jsonBuffer);
SmallVector<Attribute> symbols;
extractHierarchyFromTop(op, **symbolTable, os, symbols);
auto builder = ImplicitLocOpBuilder::atBlockEnd(
UnknownLoc::get(mlirModule.getContext()), mlirModule.getBody());
emit::FileOp::create(builder, file.getFilename(), [&] {
sv::VerbatimOp::create(builder, jsonBuffer, ValueRange{},
builder.getArrayAttr(symbols));
});
}
}
markAllAnalysesPreserved();
}