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);
71 if (!dependencyDecl) {
75 auto &clsMap = classToMethodMap[clsDecl];
76 for (
auto methodDecl : dependencyDecl.getBody().getOps<ClassMethodDeclOp>()) {
79 auto &mapEntry = clsMap[methodDecl.getSymName()];
83 std::optional<SymbolRefAttr> impl;
84 if (methodDecl.getImpl().has_value()) {
85 impl = methodDecl.getImpl().value();
92 if (dependencyDecl.getBase().has_value())
93 collectClassDependencies(mod, symTab, clsDecl,
94 dependencyDecl.getBase().value());
95 if (dependencyDecl.getImplementedInterfaces().has_value())
96 for (
auto intf : dependencyDecl.getImplementedInterfacesAttr())
97 collectClassDependencies(mod, symTab, clsDecl, cast<SymbolRefAttr>(intf));
100void CreateVTablesPass::collectClasses(ModuleOp mod, SymbolTable &symTab) {
101 for (
auto clsDecl : mod.getBodyRegion().getOps<ClassDeclOp>()) {
102 auto &clsMap = classToMethodMap[clsDecl];
106 collectClassDependencies(mod, symTab, clsDecl, SymbolRefAttr::get(clsDecl));
111 return llvm::all_of(methods,
112 [](
const auto &kv) {
return !kv.second.has_value(); });
116 return llvm::all_of(methods,
117 [](
const auto &kv) {
return kv.second.has_value(); });
122 auto base = SymbolRefAttr::get(clsDecl);
123 auto suffix = mlir::FlatSymbolRefAttr::get(clsDecl.getContext(),
"vtable");
124 auto vTableName = mlir::SymbolRefAttr::get(base.getRootReference(), {suffix});
128void CreateVTablesPass::emitVTablePerDependencyClass(
129 ModuleOp mod, SymbolTable &symTab, OpBuilder &builder, ClassDeclOp &clsDecl,
130 SymbolRefAttr dependencyName) {
132 auto dependencyDecl =
133 symTab.lookupNearestSymbolFrom<ClassDeclOp>(mod, dependencyName);
135 auto clsMethodMap = classToMethodMap[clsDecl];
136 auto depMethodMap = classToMethodMap[dependencyDecl];
139 if (depMethodMap.empty())
145 VTableOp::create(builder, dependencyDecl.getLoc(), vTableName);
146 auto ®ion = clsVTable.getRegion();
147 auto &block = region.emplaceBlock();
149 OpBuilder::InsertionGuard g(builder);
150 builder.setInsertionPointToEnd(&block);
153 if (dependencyDecl.getBase().has_value())
154 emitVTablePerDependencyClass(mod, symTab, builder, clsDecl,
155 dependencyDecl.getBase().value());
158 if (dependencyDecl.getImplementedInterfaces().has_value())
159 for (
auto intf : dependencyDecl.getImplementedInterfacesAttr())
160 emitVTablePerDependencyClass(mod, symTab, builder, clsDecl,
161 cast<SymbolRefAttr>(intf));
164 for (
auto methodDecl : dependencyDecl.getBody().getOps<ClassMethodDeclOp>()) {
165 auto methodName = methodDecl.getSymName();
166 VTableEntryOp::create(builder, methodDecl.getLoc(), methodName,
167 clsMethodMap[methodName].value());
171void CreateVTablesPass::emitVTablePerClass(ModuleOp mod, SymbolTable &symTab,
172 OpBuilder &builder) {
174 for (
auto [clsDecl, methodMap] : classToMethodMap) {
179 <<
"Class declaration " << clsDecl.getSymName()
180 <<
" is malformed; some methods are abstract and some are concrete, "
181 "which is not legal in System Verilog.";
191 if (symTab.lookupNearestSymbolFrom<VTableOp>(mod, vTableName))
194 builder.setInsertionPointAfter(clsDecl);
196 emitVTablePerDependencyClass(mod, symTab, builder, clsDecl,
197 SymbolRefAttr::get(clsDecl));
201void CreateVTablesPass::runOnOperation() {
202 ModuleOp mod = getOperation();
203 SymbolTable symTab(mod);
204 collectClasses(mod, symTab);
205 mlir::OpBuilder builder = mlir::OpBuilder::atBlockBegin(mod.getBody());
206 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.