18#define GEN_PASS_DEF_CREATEVTABLES
19#include "circt/Dialect/Moore/MoorePasses.h.inc"
28using MethodMap = llvm::DenseMap<StringRef, std::optional<SymbolRefAttr>>;
29using ClassMap = llvm::DenseMap<ClassDeclOp, MethodMap>;
31struct CreateVTablesPass
32 :
public circt::moore::impl::CreateVTablesBase<CreateVTablesPass> {
33 void runOnOperation()
override;
37 ClassMap classToMethodMap;
39 void collectClasses(ModuleOp mod, SymbolTable &symTab);
42 void collectClassDependencies(ModuleOp mod, SymbolTable &symTab,
44 SymbolRefAttr dependencyName);
47 void emitVTablePerClass(ModuleOp mod, SymbolTable &symTab,
49 void emitVTablePerDependencyClass(ModuleOp mod, SymbolTable &symTab,
50 OpBuilder &builder, ClassDeclOp &clsDecl,
51 SymbolRefAttr dependencyName);
56 return std::make_unique<CreateVTablesPass>();
59void CreateVTablesPass::collectClassDependencies(ModuleOp mod,
62 SymbolRefAttr dependencyName) {
64 symTab.lookupNearestSymbolFrom<ClassDeclOp>(mod, dependencyName);
70 if (!dependencyDecl) {
74 auto &clsMap = classToMethodMap[clsDecl];
75 for (
auto methodDecl : dependencyDecl.getBody().getOps<ClassMethodDeclOp>()) {
78 auto &mapEntry = clsMap[methodDecl.getSymName()];
82 std::optional<SymbolRefAttr>
impl;
83 if (methodDecl.getImpl().has_value()) {
84 impl = methodDecl.getImpl().value();
91 if (dependencyDecl.getBase().has_value())
92 collectClassDependencies(mod, symTab, clsDecl,
93 dependencyDecl.getBase().value());
94 if (dependencyDecl.getImplementedInterfaces().has_value())
95 for (
auto intf : dependencyDecl.getImplementedInterfacesAttr())
96 collectClassDependencies(mod, symTab, clsDecl, cast<SymbolRefAttr>(intf));
99void CreateVTablesPass::collectClasses(ModuleOp mod, SymbolTable &symTab) {
100 for (
auto clsDecl : mod.getBodyRegion().getOps<ClassDeclOp>()) {
101 auto &clsMap = classToMethodMap[clsDecl];
105 collectClassDependencies(mod, symTab, clsDecl, SymbolRefAttr::get(clsDecl));
110 return llvm::all_of(methods,
111 [](
const auto &kv) {
return !kv.second.has_value(); });
115 return llvm::all_of(methods,
116 [](
const auto &kv) {
return kv.second.has_value(); });
121 auto base = SymbolRefAttr::get(clsDecl);
122 auto suffix = mlir::FlatSymbolRefAttr::get(clsDecl.getContext(),
"vtable");
123 auto vTableName = mlir::SymbolRefAttr::get(base.getRootReference(), {suffix});
127void CreateVTablesPass::emitVTablePerDependencyClass(
128 ModuleOp mod, SymbolTable &symTab, OpBuilder &builder, ClassDeclOp &clsDecl,
129 SymbolRefAttr dependencyName) {
131 auto dependencyDecl =
132 symTab.lookupNearestSymbolFrom<ClassDeclOp>(mod, dependencyName);
134 auto clsMethodMap = classToMethodMap[clsDecl];
135 auto depMethodMap = classToMethodMap[dependencyDecl];
138 if (depMethodMap.empty())
144 VTableOp::create(builder, dependencyDecl.getLoc(), vTableName);
145 auto ®ion = clsVTable.getRegion();
146 auto &block = region.emplaceBlock();
148 OpBuilder::InsertionGuard g(builder);
149 builder.setInsertionPointToEnd(&block);
152 if (dependencyDecl.getBase().has_value())
153 emitVTablePerDependencyClass(mod, symTab, builder, clsDecl,
154 dependencyDecl.getBase().value());
157 if (dependencyDecl.getImplementedInterfaces().has_value())
158 for (
auto intf : dependencyDecl.getImplementedInterfacesAttr())
159 emitVTablePerDependencyClass(mod, symTab, builder, clsDecl,
160 cast<SymbolRefAttr>(intf));
163 for (
auto methodDecl : dependencyDecl.getBody().getOps<ClassMethodDeclOp>()) {
164 auto methodName = methodDecl.getSymName();
165 VTableEntryOp::create(builder, methodDecl.getLoc(), methodName,
166 clsMethodMap[methodName].value());
170void CreateVTablesPass::emitVTablePerClass(ModuleOp mod, SymbolTable &symTab,
171 OpBuilder &builder) {
173 for (
auto [clsDecl, methodMap] : classToMethodMap) {
178 <<
"Class declaration " << clsDecl.getSymName()
179 <<
" is malformed; some methods are abstract and some are concrete, "
180 "which is not legal in System Verilog.";
190 if (symTab.lookupNearestSymbolFrom<VTableOp>(mod, vTableName))
193 builder.setInsertionPointAfter(clsDecl);
195 emitVTablePerDependencyClass(mod, symTab, builder, clsDecl,
196 SymbolRefAttr::get(clsDecl));
200void CreateVTablesPass::runOnOperation() {
201 ModuleOp mod = getOperation();
202 SymbolTable symTab(mod);
203 collectClasses(mod, symTab);
204 mlir::OpBuilder builder = mlir::OpBuilder::atBlockBegin(mod.getBody());
205 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.