18#define GEN_PASS_DEF_CREATEVTABLES
19#include "circt/Dialect/Moore/MoorePasses.h.inc"
29using MethodMap = llvm::DenseMap<StringRef, std::optional<SymbolRefAttr>>;
30using ClassMap = llvm::DenseMap<ClassDeclOp, MethodMap>;
32struct CreateVTablesPass
33 :
public circt::moore::impl::CreateVTablesBase<CreateVTablesPass> {
34 void runOnOperation()
override;
38 ClassMap classToMethodMap;
40 void collectClasses(ModuleOp mod, SymbolTable &symTab);
43 void collectClassDependencies(ModuleOp mod, SymbolTable &symTab,
45 SymbolRefAttr dependencyName);
48 void emitVTablePerClass(ModuleOp mod, SymbolTable &symTab,
50 void emitVTablePerDependencyClass(ModuleOp mod, SymbolTable &symTab,
51 OpBuilder &builder, ClassDeclOp &clsDecl,
52 SymbolRefAttr dependencyName);
57 return std::make_unique<CreateVTablesPass>();
60void CreateVTablesPass::collectClassDependencies(ModuleOp mod,
63 SymbolRefAttr dependencyName) {
65 symTab.lookupNearestSymbolFrom<ClassDeclOp>(mod, dependencyName);
67 auto &clsMap = classToMethodMap[clsDecl];
68 for (
auto methodDecl : dependencyDecl.getBody().getOps<ClassMethodDeclOp>()) {
71 auto &mapEntry = clsMap[methodDecl.getSymName()];
75 std::optional<SymbolRefAttr> impl;
76 if (methodDecl.getImpl().has_value()) {
77 impl = methodDecl.getImpl().value();
84 if (dependencyDecl.getBase().has_value())
85 collectClassDependencies(mod, symTab, clsDecl,
86 dependencyDecl.getBase().value());
87 if (dependencyDecl.getImplementedInterfaces().has_value())
88 for (
auto intf : dependencyDecl.getImplementedInterfacesAttr())
89 collectClassDependencies(mod, symTab, clsDecl, cast<SymbolRefAttr>(intf));
92void CreateVTablesPass::collectClasses(ModuleOp mod, SymbolTable &symTab) {
93 for (
auto clsDecl : mod.getBodyRegion().getOps<ClassDeclOp>()) {
94 auto &clsMap = classToMethodMap[clsDecl];
98 collectClassDependencies(mod, symTab, clsDecl, SymbolRefAttr::get(clsDecl));
103 return llvm::all_of(methods,
104 [](
const auto &kv) {
return !kv.second.has_value(); });
108 return llvm::all_of(methods,
109 [](
const auto &kv) {
return kv.second.has_value(); });
114 auto base = SymbolRefAttr::get(clsDecl);
115 auto suffix = mlir::FlatSymbolRefAttr::get(clsDecl.getContext(),
"vtable");
116 auto vTableName = mlir::SymbolRefAttr::get(base.getRootReference(), {suffix});
120void CreateVTablesPass::emitVTablePerDependencyClass(
121 ModuleOp mod, SymbolTable &symTab, OpBuilder &builder, ClassDeclOp &clsDecl,
122 SymbolRefAttr dependencyName) {
124 auto dependencyDecl =
125 symTab.lookupNearestSymbolFrom<ClassDeclOp>(mod, dependencyName);
127 auto clsMethodMap = classToMethodMap[clsDecl];
128 auto depMethodMap = classToMethodMap[dependencyDecl];
131 if (depMethodMap.empty())
137 VTableOp::create(builder, dependencyDecl.getLoc(), vTableName);
138 auto ®ion = clsVTable.getRegion();
139 auto &block = region.emplaceBlock();
141 OpBuilder::InsertionGuard g(builder);
142 builder.setInsertionPointToEnd(&block);
145 if (dependencyDecl.getBase().has_value())
146 emitVTablePerDependencyClass(mod, symTab, builder, clsDecl,
147 dependencyDecl.getBase().value());
150 if (dependencyDecl.getImplementedInterfaces().has_value())
151 for (
auto intf : dependencyDecl.getImplementedInterfacesAttr())
152 emitVTablePerDependencyClass(mod, symTab, builder, clsDecl,
153 cast<SymbolRefAttr>(intf));
156 for (
auto methodDecl : dependencyDecl.getBody().getOps<ClassMethodDeclOp>()) {
157 auto methodName = methodDecl.getSymName();
158 VTableEntryOp::create(builder, methodDecl.getLoc(), methodName,
159 clsMethodMap[methodName].value());
163void CreateVTablesPass::emitVTablePerClass(ModuleOp mod, SymbolTable &symTab,
164 OpBuilder &builder) {
166 for (
auto [clsDecl, methodMap] : classToMethodMap) {
171 <<
"Class declaration " << clsDecl.getSymName()
172 <<
" is malformed; some methods are abstract and some are concrete, "
173 "which is not legal in System Verilog.";
183 if (symTab.lookupNearestSymbolFrom<VTableOp>(mod, vTableName))
186 builder.setInsertionPointAfter(clsDecl);
188 emitVTablePerDependencyClass(mod, symTab, builder, clsDecl,
189 SymbolRefAttr::get(clsDecl));
193void CreateVTablesPass::runOnOperation() {
194 ModuleOp mod = getOperation();
195 SymbolTable symTab(mod);
196 collectClasses(mod, symTab);
197 mlir::OpBuilder builder = mlir::OpBuilder::atBlockBegin(mod.getBody());
198 emitVTablePerClass(mod, symTab, builder);
static bool noneHaveImpl(const MethodMap &methods)
static bool allHaveImpl(const MethodMap &methods)
static SymbolRefAttr getVTableName(ClassDeclOp &clsDecl)
std::unique_ptr< mlir::Pass > createVTablesPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.