23 #include "mlir/IR/BuiltinOps.h"
24 #include "mlir/IR/PatternMatch.h"
25 #include "mlir/IR/Threading.h"
26 #include "mlir/Pass/Pass.h"
27 #include "mlir/Support/LogicalResult.h"
28 #include "mlir/Transforms/DialectConversion.h"
29 #include "llvm/ADT/DepthFirstIterator.h"
30 #include "llvm/ADT/STLExtras.h"
31 #include "llvm/Support/raw_ostream.h"
35 #define GEN_PASS_DEF_LOWERCLASSES
36 #include "circt/Dialect/FIRRTL/Passes.h.inc"
41 using namespace circt;
48 auto moduleLike = node->
getModule<FModuleLike>();
52 if (isa<firrtl::ClassLike>(moduleLike.getOperation()))
56 if (moduleLike.isPublic())
60 bool hasClassPorts = llvm::any_of(moduleLike.getPorts(), [](
PortInfo port) {
61 return isa<PropertyType>(port.type);
69 for (
auto *instance : *node) {
70 if (
auto op = instance->getInstance<FInstanceLike>())
71 for (
auto result : op->getResults())
72 if (type_isa<PropertyType>(result.getType()))
83 PathInfo(Location loc,
bool canBeInstanceTarget, FlatSymbolRefAttr symRef,
84 StringAttr altBasePathModule)
85 : loc(loc), canBeInstanceTarget(canBeInstanceTarget), symRef(symRef),
86 altBasePathModule(altBasePathModule) {
87 assert(symRef &&
"symRef must not be null");
91 std::optional<Location> loc = std::nullopt;
94 bool canBeInstanceTarget =
false;
97 FlatSymbolRefAttr symRef =
nullptr;
101 StringAttr altBasePathModule =
nullptr;
105 struct PathInfoTable {
108 void addAltBasePathRoot(StringAttr rootModuleName) {
109 altBasePathRoots.insert(rootModuleName);
114 void addAltBasePathPassthrough(StringAttr passthroughModuleName,
115 StringAttr rootModuleName) {
116 auto &rootSequence = altBasePathsPassthroughs[passthroughModuleName];
117 rootSequence.push_back(rootModuleName);
121 llvm::iterator_range<SmallPtrSetImpl<StringAttr>::iterator>
122 getAltBasePathRoots()
const {
123 return llvm::make_range(altBasePathRoots.begin(), altBasePathRoots.end());
128 size_t getNumAltBasePaths(StringAttr passthroughModuleName)
const {
129 return altBasePathsPassthroughs.lookup(passthroughModuleName).size();
134 llvm::iterator_range<const StringAttr *>
135 getRootsForPassthrough(StringAttr passthroughModuleName)
const {
136 auto it = altBasePathsPassthroughs.find(passthroughModuleName);
137 assert(it != altBasePathsPassthroughs.end() &&
138 "expected passthrough module to already exist");
139 return llvm::make_range(it->second.begin(), it->second.end());
144 void collectAltBasePaths(Operation *instance, StringAttr moduleNameAttr,
145 SmallVectorImpl<Value> &result)
const {
146 auto altBasePaths = altBasePathsPassthroughs.lookup(moduleNameAttr);
147 auto parent = instance->getParentOfType<om::ClassOp>();
150 for (
auto [i, altBasePath] : llvm::enumerate(altBasePaths)) {
151 if (parent.getName().starts_with(altBasePath)) {
153 result.push_back(instance->getBlock()->getArgument(0));
157 auto basePath = instance->getBlock()->getArgument(1 + i);
158 assert(isa<om::BasePathType>(basePath.getType()) &&
159 "expected a passthrough base path");
160 result.push_back(basePath);
166 DenseMap<DistinctAttr, PathInfo> table;
171 SmallPtrSet<StringAttr, 16> altBasePathRoots;
175 DenseMap<StringAttr, SmallVector<StringAttr>> altBasePathsPassthroughs;
179 static constexpr StringRef kClassNameSuffix =
"_Class";
190 struct ClassLoweringState {
191 FModuleLike moduleLike;
192 std::vector<hw::HierPathOp> paths;
195 struct LoweringState {
196 PathInfoTable pathInfoTable;
197 DenseMap<om::ClassLike, ClassLoweringState> classLoweringStateTable;
201 struct RtlPortsInfo {
202 firrtl::PathOp containingModuleRef;
207 struct LowerClassesPass
208 :
public circt::firrtl::impl::LowerClassesBase<LowerClassesPass> {
209 void runOnOperation()
override;
213 hw::InnerSymbolNamespaceCollection &namespaces,
215 SymbolTable &symbolTable);
218 bool shouldCreateClass(StringAttr modName);
221 om::ClassLike createClass(FModuleLike moduleLike,
222 const PathInfoTable &pathInfoTable,
223 std::mutex &intraPassMutex);
226 void lowerClassLike(FModuleLike moduleLike, om::ClassLike classLike,
227 const PathInfoTable &pathInfoTable);
228 void lowerClass(om::ClassOp classOp, FModuleLike moduleLike,
229 const PathInfoTable &pathInfoTable);
230 void lowerClassExtern(ClassExternOp classExternOp, FModuleLike moduleLike);
233 LogicalResult updateInstances(Operation *op,
InstanceGraph &instanceGraph,
234 const LoweringState &state,
235 const PathInfoTable &pathInfoTable,
236 std::mutex &intraPassMutex);
239 void createAllRtlPorts(
const PathInfoTable &pathInfoTable,
240 hw::InnerSymbolNamespaceCollection &namespaces,
244 LogicalResult dialectConversion(
245 Operation *op,
const PathInfoTable &pathInfoTable,
246 const DenseMap<StringAttr, firrtl::ClassType> &classTypeTable);
249 DenseMap<StringAttr, bool> shouldCreateClassMemo;
252 SmallVector<RtlPortsInfo> rtlPortsToCreate;
260 hw::InnerSymbolNamespaceCollection &namespaces,
HierPathCache &cache,
261 PathInfoTable &pathInfoTable,
const SymbolTable &symbolTable,
262 const DenseMap<DistinctAttr, FModuleOp> &owningModules);
264 PathTracker(FModuleLike module,
265 hw::InnerSymbolNamespaceCollection &namespaces,
266 InstanceGraph &instanceGraph,
const SymbolTable &symbolTable,
267 const DenseMap<DistinctAttr, FModuleOp> &owningModules)
268 : module(module), moduleNamespace(namespaces[module]),
269 namespaces(namespaces), instanceGraph(instanceGraph),
270 symbolTable(symbolTable), owningModules(owningModules) {}
273 struct PathInfoTableEntry {
276 StringAttr altBasePathModule;
282 LogicalResult runOnModule();
285 FailureOr<AnnotationSet> processPathTrackers(
const AnnoTarget &target);
287 LogicalResult updatePathInfoTable(PathInfoTable &pathInfoTable,
292 FailureOr<bool> getOrComputeNeedsAltBasePath(Location loc,
293 StringAttr moduleName,
294 FModuleOp owningModule,
299 hw::InnerSymbolNamespace &moduleNamespace;
300 hw::InnerSymbolNamespaceCollection &namespaces;
301 DenseMap<std::pair<StringAttr, FModuleOp>,
bool> needsAltBasePathCache;
305 const SymbolTable &symbolTable;
306 const DenseMap<DistinctAttr, FModuleOp> &owningModules;
309 SmallVector<PathInfoTableEntry> entries;
310 SetVector<StringAttr> altBasePathRoots;
315 static constexpr StringRef kContainingModuleName =
"containingModule";
316 static constexpr StringRef kPortsName =
"ports";
317 static constexpr StringRef kRtlPortClassName =
"RtlPort";
319 static Type getRtlPortsType(MLIRContext *context) {
325 static void createRtlPorts(
const RtlPortsInfo &rtlPortToCreate,
326 const PathInfoTable &pathInfoTable,
327 hw::InnerSymbolNamespaceCollection &namespaces,
329 firrtl::PathOp containingModuleRef = rtlPortToCreate.containingModuleRef;
330 Value basePath = rtlPortToCreate.basePath;
331 om::ObjectOp
object = rtlPortToCreate.object;
334 OpBuilder::InsertionGuard guard(builder);
335 builder.setInsertionPoint(
object);
339 FlatSymbolRefAttr containingModulePathRef =
340 pathInfoTable.table.at(containingModuleRef.getTarget()).symRef;
344 hw::HierPathOp containingModulePath =
345 symbolTable.lookup<hw::HierPathOp>(containingModulePathRef.getAttr());
347 assert(containingModulePath.isModule() &&
348 "expected containing module path to target a module");
350 StringAttr moduleName = containingModulePath.leafMod();
352 FModuleLike mod = symbolTable.lookup<FModuleLike>(moduleName);
353 MLIRContext *ctx = mod.getContext();
354 Location loc = mod.getLoc();
362 SmallVector<Value> ports;
363 for (
unsigned i = 0, e = mod.getNumPorts(); i < e; ++i) {
365 auto portType = type_dyn_cast<FIRRTLBaseType>(mod.getPortType(i));
366 if (!portType || portType.getBitWidthOrSentinel() == 0)
375 getInnerRefTo({portTarget.getPortNo(), portTarget.getOp(), 0},
376 [&](FModuleLike m) -> hw::InnerSymbolNamespace & {
377 return namespaces[m];
380 FlatSymbolRefAttr portPathRef =
383 auto portPath = builder.create<om::PathCreateOp>(
390 StringRef portDirectionName =
391 mod.getPortDirection(i) == Direction::Out ?
"Output" :
"Input";
393 auto portDirection = builder.create<om::ConstantOp>(
399 auto portWidth = builder.create<om::ConstantOp>(
403 portType.getBitWidthOrSentinel())));
407 auto portObj = builder.create<om::ObjectOp>(
408 loc, portClassType, portClassName,
409 ArrayRef<Value>{portPath, portDirection, portWidth});
411 ports.push_back(portObj);
416 auto portsList = builder.create<om::ListCreateOp>(
418 getRtlPortsType(builder.getContext()), ports);
420 object.getActualParamsMutable().append({portsList});
427 hw::InnerSymbolNamespaceCollection &namespaces,
429 const SymbolTable &symbolTable,
430 const DenseMap<DistinctAttr, FModuleOp> &owningModules) {
433 for (
auto *node : instanceGraph)
434 if (
auto module = node->
getModule<FModuleLike>())
435 (void)namespaces.get(module);
437 for (
auto *node : instanceGraph)
438 if (
auto module = node->
getModule<FModuleLike>()) {
440 if (isa<firrtl::ClassOp, firrtl::ExtClassOp>(module))
442 PathTracker tracker(module, namespaces, instanceGraph, symbolTable,
444 if (failed(tracker.runOnModule()))
446 if (failed(tracker.updatePathInfoTable(pathInfoTable, cache)))
453 LogicalResult PathTracker::runOnModule() {
454 auto processAndUpdateAnnoTarget = [&](
AnnoTarget target) -> LogicalResult {
455 auto anno = processPathTrackers(target);
458 target.setAnnotations(*anno);
463 if (failed(processAndUpdateAnnoTarget(
OpAnnoTarget(module))))
467 SmallVector<Attribute> portAnnotations;
468 portAnnotations.reserve(module.getNumPorts());
469 for (
unsigned i = 0, e = module.getNumPorts(); i < e; ++i) {
473 portAnnotations.push_back(annos->getArrayAttr());
476 module.setPortAnnotationsAttr(
480 auto result = module.walk([&](hw::InnerSymbolOpInterface op) {
481 if (failed(processAndUpdateAnnoTarget(
OpAnnoTarget(op))))
482 return WalkResult::interrupt();
483 return WalkResult::advance();
486 if (result.wasInterrupted())
494 PathTracker::getOrComputeNeedsAltBasePath(Location loc, StringAttr moduleName,
495 FModuleOp owningModule,
498 auto it = needsAltBasePathCache.find({moduleName, owningModule});
499 if (it != needsAltBasePathCache.end())
501 bool needsAltBasePath =
false;
502 auto *node = instanceGraph.lookup(moduleName);
512 needsAltBasePath =
true;
518 auto diag = mlir::emitError(loc)
519 <<
"unable to uniquely resolve target due "
520 "to multiple instantiation";
521 for (
auto *use : node->
uses())
522 diag.attachNote(use->getInstance().getLoc()) <<
"instance here";
525 node = (*node->
usesBegin())->getParent();
527 needsAltBasePathCache[{moduleName, owningModule}] = needsAltBasePath;
528 return needsAltBasePath;
531 FailureOr<AnnotationSet>
532 PathTracker::processPathTrackers(
const AnnoTarget &target) {
535 auto *op = target.
getOp();
536 annotations.removeAnnotations([&](
Annotation anno) {
542 if (!anno.
isClass(
"circt.tracker"))
546 auto id = anno.
getMember<DistinctAttr>(
"id");
548 op->emitError(
"circt.tracker annotation missing id field");
558 if (
auto portTarget = dyn_cast<PortAnnoTarget>(target)) {
560 getInnerRefTo({portTarget.getPortNo(), portTarget.getOp(), fieldID},
561 [&](FModuleLike module) -> hw::InnerSymbolNamespace & {
562 return moduleNamespace;
564 }
else if (
auto module = dyn_cast<FModuleLike>(op)) {
565 assert(!fieldID &&
"field not valid for modules");
570 [&](FModuleLike module) -> hw::InnerSymbolNamespace & {
571 return moduleNamespace;
576 SmallVector<Attribute> path;
579 path.push_back(targetSym);
581 auto moduleName = target.
getModule().getModuleNameAttr();
584 hw::HierPathOp hierPathOp;
585 if (
auto hierName = anno.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal")) {
587 dyn_cast<hw::HierPathOp>(symbolTable.lookup(hierName.getAttr()));
589 op->emitError(
"annotation does not point at a HierPathOp");
597 auto owningModule = owningModules.lookup(
id);
599 PathInfoTableEntry entry;
603 entries.push_back(entry);
610 auto oldPath = hierPathOp.getNamepath().getValue();
615 bool pathContainsOwningModule =
false;
616 size_t owningModuleIndex = 0;
617 for (
auto [idx, pathFramgent] : llvm::enumerate(oldPath)) {
618 if (
auto innerRef = dyn_cast<hw::InnerRefAttr>(pathFramgent)) {
619 if (innerRef.getModule() == owningModule.getModuleNameAttr()) {
620 pathContainsOwningModule =
true;
621 owningModuleIndex = idx;
623 }
else if (
auto symRef = dyn_cast<FlatSymbolRefAttr>(pathFramgent)) {
624 if (symRef.getAttr() == owningModule.getModuleNameAttr()) {
625 pathContainsOwningModule =
true;
626 owningModuleIndex = idx;
631 if (pathContainsOwningModule) {
633 moduleName = owningModule.getModuleNameAttr();
637 llvm::append_range(path, llvm::reverse(oldPath.drop_back().drop_front(
638 owningModuleIndex)));
641 moduleName = cast<hw::InnerRefAttr>(oldPath.front()).getModule();
644 llvm::append_range(path, llvm::reverse(oldPath.drop_back()));
649 auto needsAltBasePath = getOrComputeNeedsAltBasePath(
650 op->getLoc(), moduleName, owningModule, hierPathOp);
651 if (failed(needsAltBasePath)) {
663 if (!hierPathOp && !needsAltBasePath.value())
681 std::reverse(path.begin(), path.end());
686 StringAttr altBasePathModule;
687 if (*needsAltBasePath) {
689 TypeSwitch<Attribute, StringAttr>(path.front())
690 .Case<FlatSymbolRefAttr>([](
auto a) {
return a.getAttr(); })
691 .Case<hw::InnerRefAttr>([](
auto a) {
return a.getModule(); });
693 altBasePathRoots.insert(altBasePathModule);
697 entries.push_back({op, id, altBasePathModule, pathAttr});
709 LogicalResult PathTracker::updatePathInfoTable(PathInfoTable &pathInfoTable,
711 for (
auto root : altBasePathRoots)
712 pathInfoTable.addAltBasePathRoot(root);
714 for (
const auto &entry : entries) {
716 auto [it, inserted] = pathInfoTable.table.try_emplace(entry.id);
717 auto &pathInfo = it->second;
719 assert(pathInfo.loc.has_value() &&
"all PathInfo should have a Location");
720 auto diag = emitError(pathInfo.loc.value(),
721 "path identifier already found, paths must resolve "
722 "to a unique target");
723 diag.attachNote(entry.op->getLoc()) <<
"other path identifier here";
729 bool canBeInstanceTarget = isa<InstanceOp, FModuleLike>(entry.op);
731 if (entry.pathAttr) {
732 pathInfo = {entry.op->getLoc(), canBeInstanceTarget,
733 cache.
getRefFor(entry.pathAttr), entry.altBasePathModule};
735 pathInfo.loc = entry.op->getLoc();
736 pathInfo.canBeInstanceTarget = canBeInstanceTarget;
748 LogicalResult LowerClassesPass::processPaths(
750 hw::InnerSymbolNamespaceCollection &namespaces,
HierPathCache &cache,
751 PathInfoTable &pathInfoTable, SymbolTable &symbolTable) {
752 auto circuit = getOperation();
756 DenseMap<DistinctAttr, FModuleOp> owningModules;
757 std::vector<Operation *> declarations;
758 auto result = circuit.walk([&](Operation *op) {
759 if (
auto pathOp = dyn_cast<PathOp>(op)) {
761 auto owningModule = owningModuleCache.lookup(pathOp);
764 pathOp->emitError(
"path does not have a single owning module");
765 return WalkResult::interrupt();
767 auto target = pathOp.getTargetAttr();
768 auto [it, inserted] = owningModules.try_emplace(target, owningModule);
771 if (!inserted && it->second != owningModule) {
773 <<
"path reference " << target <<
" has conflicting owning modules "
774 << it->second.getModuleNameAttr() <<
" and "
775 << owningModule.getModuleNameAttr();
776 return WalkResult::interrupt();
779 return WalkResult::advance();
782 if (result.wasInterrupted())
786 pathInfoTable, symbolTable, owningModules)))
791 for (
auto rootModule : pathInfoTable.getAltBasePathRoots()) {
796 auto start = llvm::df_begin(node);
797 auto end = llvm::df_end(node);
807 if (!shouldCreateClass(
808 it->getModule<FModuleLike>().getModuleNameAttr())) {
809 it = it.skipChildren();
814 if (it->begin() == it->end()) {
820 StringAttr passthroughModule = it->getModule().getModuleNameAttr();
821 pathInfoTable.addAltBasePathPassthrough(passthroughModule, rootModule);
831 void LowerClassesPass::runOnOperation() {
832 MLIRContext *ctx = &getContext();
833 auto intraPassMutex = std::mutex();
836 CircuitOp circuit = getOperation();
840 SymbolTable &symbolTable = getAnalysis<SymbolTable>();
842 hw::InnerSymbolNamespaceCollection namespaces;
846 for (
auto *node : instanceGraph)
847 if (
auto moduleLike = node->
getModule<firrtl::FModuleLike>())
848 shouldCreateClassMemo.insert({moduleLike.getModuleNameAttr(),
false});
850 parallelForEach(circuit.getContext(), instanceGraph,
852 if (auto moduleLike = node->getModule<FModuleLike>())
853 shouldCreateClassMemo[moduleLike.getModuleNameAttr()] =
854 shouldCreateClassImpl(node);
858 PathInfoTable pathInfoTable;
859 if (failed(processPaths(instanceGraph, namespaces, cache, pathInfoTable,
868 DenseMap<StringAttr, firrtl::ClassType> classTypeTable;
869 for (
auto *node : instanceGraph) {
870 auto moduleLike = node->
getModule<firrtl::FModuleLike>();
874 if (shouldCreateClass(moduleLike.getModuleNameAttr())) {
875 auto omClass = createClass(moduleLike, pathInfoTable, intraPassMutex);
876 auto &classLoweringState =
loweringState.classLoweringStateTable[omClass];
877 classLoweringState.moduleLike = moduleLike;
884 for (
auto *instance : *node) {
885 auto inst = instance->
getInstance<firrtl::InstanceOp>();
889 auto module = instance->getTarget()->getModule<FModuleLike>();
890 if (module && shouldCreateClass(module.getModuleNameAttr())) {
892 {inst, 0}, [&](FModuleLike module) -> hw::InnerSymbolNamespace & {
893 return namespaces[module];
895 SmallVector<Attribute> path = {targetSym};
897 auto hierPath = cache.
getOpFor(pathAttr);
898 classLoweringState.paths.push_back(hierPath);
903 dyn_cast<firrtl::ClassLike>(moduleLike.getOperation()))
904 classTypeTable[classLike.getNameAttr()] = classLike.getInstanceType();
909 mlir::parallelForEach(ctx,
loweringState.classLoweringStateTable,
910 [
this, &pathInfoTable](
auto &entry) {
911 const auto &[classLike, state] = entry;
912 lowerClassLike(state.moduleLike, classLike,
917 for (
auto &[omClass, state] :
loweringState.classLoweringStateTable) {
918 if (isa<firrtl::ClassLike>(state.moduleLike.getOperation())) {
920 for (
auto *use : llvm::make_early_inc_range(node->
uses()))
922 instanceGraph.erase(node);
923 state.moduleLike.erase();
928 SmallVector<Operation *> objectContainers;
929 for (
auto &op : circuit.getOps())
930 if (isa<FModuleOp, om::ClassLike>(op))
931 objectContainers.push_back(&op);
935 mlir::failableParallelForEach(ctx, objectContainers, [&](
auto *op) {
937 pathInfoTable, intraPassMutex);
939 return signalPassFailure();
942 if (!rtlPortsToCreate.empty())
943 createAllRtlPorts(pathInfoTable, namespaces, cache);
947 mlir::failableParallelForEach(ctx, objectContainers, [&](
auto *op) {
948 return dialectConversion(op, pathInfoTable, classTypeTable);
950 return signalPassFailure();
953 markAnalysesPreserved<InstanceGraph>();
956 rtlPortsToCreate.clear();
960 return std::make_unique<LowerClassesPass>();
964 bool LowerClassesPass::shouldCreateClass(StringAttr modName) {
966 return shouldCreateClassMemo.at(modName);
970 SmallVector<Attribute> &fieldNames,
971 SmallVector<NamedAttribute> &fieldTypes) {
972 if (hasContainingModule) {
973 auto name = builder.getStringAttr(kPortsName);
974 fieldNames.push_back(name);
975 fieldTypes.push_back(NamedAttribute(
976 name,
TypeAttr::get(getRtlPortsType(builder.getContext()))));
982 ArrayRef<StringRef> formalParamNames,
983 bool hasContainingModule) {
984 SmallVector<Attribute> fieldNames;
985 SmallVector<NamedAttribute> fieldTypes;
986 for (
unsigned i = 0, e = moduleLike.getNumPorts(); i < e; ++i) {
987 auto type = moduleLike.getPortType(i);
988 if (!isa<PropertyType>(type))
991 auto direction = moduleLike.getPortDirection(i);
992 if (direction != Direction::In) {
993 auto name = moduleLike.getPortNameAttr(i);
994 fieldNames.push_back(name);
995 fieldTypes.push_back(NamedAttribute(name,
TypeAttr::get(type)));
1000 return builder.create<om::ClassExternOp>(
1001 moduleLike.getLoc(), name, formalParamNames, fieldNames, fieldTypes);
1004 static om::ClassLike
convertClass(FModuleLike moduleLike, OpBuilder builder,
1006 ArrayRef<StringRef> formalParamNames,
1007 bool hasContainingModule) {
1009 SmallVector<Attribute> fieldNames;
1010 SmallVector<NamedAttribute> fieldTypes;
1011 for (
auto op : llvm::make_early_inc_range(
1012 moduleLike->getRegion(0).getOps<PropAssignOp>())) {
1013 auto outputPort = dyn_cast<BlockArgument>(op.getDest());
1017 StringAttr name = moduleLike.getPortNameAttr(outputPort.getArgNumber());
1019 fieldNames.push_back(name);
1020 fieldTypes.push_back(
1021 NamedAttribute(name,
TypeAttr::get(op.getSrc().getType())));
1026 return builder.create<om::ClassOp>(moduleLike.getLoc(), name,
1027 formalParamNames, fieldNames, fieldTypes);
1031 om::ClassLike LowerClassesPass::createClass(FModuleLike moduleLike,
1032 const PathInfoTable &pathInfoTable,
1033 std::mutex &intraPassMutex) {
1035 SmallVector<StringRef> formalParamNames;
1037 formalParamNames.emplace_back(
"basepath");
1040 size_t nAltBasePaths =
1041 pathInfoTable.getNumAltBasePaths(moduleLike.getModuleNameAttr());
1042 for (
size_t i = 0; i < nAltBasePaths; ++i)
1044 moduleLike->getContext(),
"alt_basepath_" + llvm::Twine(i)));
1047 bool hasContainingModule =
false;
1048 for (
auto [index, port] : llvm::enumerate(moduleLike.getPorts())) {
1049 if (port.isInput() && isa<PropertyType>(port.type)) {
1050 formalParamNames.push_back(port.name);
1053 if (port.name.strref().starts_with(kContainingModuleName))
1054 hasContainingModule =
true;
1058 OpBuilder builder = OpBuilder::atBlockEnd(getOperation().
getBodyBlock());
1061 if (hasContainingModule)
1062 formalParamNames.push_back(kPortsName);
1065 StringRef className = moduleLike.getName();
1068 if (
auto externMod = dyn_cast<FExtModuleOp>(moduleLike.getOperation()))
1069 if (
auto defname = externMod.getDefname())
1070 className = defname.value();
1075 isa<FModuleOp, FExtModuleOp>(moduleLike) ? kClassNameSuffix :
"";
1078 om::ClassLike loweredClassOp;
1079 if (isa<firrtl::ExtClassOp, firrtl::FExtModuleOp>(
1080 moduleLike.getOperation())) {
1081 loweredClassOp =
convertExtClass(moduleLike, builder, className + suffix,
1082 formalParamNames, hasContainingModule);
1084 loweredClassOp =
convertClass(moduleLike, builder, className + suffix,
1085 formalParamNames, hasContainingModule);
1088 return loweredClassOp;
1091 void LowerClassesPass::lowerClassLike(FModuleLike moduleLike,
1092 om::ClassLike classLike,
1093 const PathInfoTable &pathInfoTable) {
1095 if (
auto classOp = dyn_cast<om::ClassOp>(classLike.getOperation())) {
1096 return lowerClass(classOp, moduleLike, pathInfoTable);
1098 if (
auto classExternOp =
1099 dyn_cast<om::ClassExternOp>(classLike.getOperation())) {
1100 return lowerClassExtern(classExternOp, moduleLike);
1102 llvm_unreachable(
"unhandled class-like op");
1105 void LowerClassesPass::lowerClass(om::ClassOp classOp, FModuleLike moduleLike,
1106 const PathInfoTable &pathInfoTable) {
1108 SmallVector<Property> inputProperties;
1109 BitVector portsToErase(moduleLike.getNumPorts());
1110 bool hasContainingModule =
false;
1111 for (
auto [index, port] : llvm::enumerate(moduleLike.getPorts())) {
1113 if (!isa<PropertyType>(port.type))
1117 if (port.isInput()) {
1118 inputProperties.push_back({index, port.name, port.type, port.loc});
1121 if (port.name.strref().starts_with(kContainingModuleName))
1122 hasContainingModule =
true;
1126 portsToErase.set(index);
1131 Block *moduleBody = &moduleLike->getRegion(0).front();
1132 Block *classBody = &classOp->getRegion(0).emplaceBlock();
1136 classBody->addArgument(basePathType, unknownLoc);
1139 size_t nAltBasePaths =
1140 pathInfoTable.getNumAltBasePaths(moduleLike.getModuleNameAttr());
1141 for (
size_t i = 0; i < nAltBasePaths; ++i)
1142 classBody->addArgument(basePathType, unknownLoc);
1145 for (
auto &op : llvm::make_early_inc_range(llvm::reverse(*moduleBody))) {
1146 if (
auto instance = dyn_cast<InstanceOp>(op)) {
1147 if (!shouldCreateClass(instance.getReferencedModuleNameAttr()))
1149 auto *clone = OpBuilder::atBlockBegin(classBody).clone(op);
1150 for (
auto result : instance.getResults()) {
1151 if (isa<PropertyType>(result.getType()))
1152 result.replaceAllUsesWith(clone->getResult(result.getResultNumber()));
1157 auto isProperty = [](
auto x) {
return isa<PropertyType>(x.getType()); };
1158 if (llvm::any_of(op.getOperands(), isProperty) ||
1159 llvm::any_of(op.getResults(), isProperty))
1160 op.moveBefore(classBody, classBody->begin());
1164 for (
auto input : inputProperties) {
1165 auto arg = classBody->addArgument(input.type, input.loc);
1166 moduleBody->getArgument(input.index).replaceAllUsesWith(arg);
1169 llvm::SmallVector<mlir::Location> fieldLocs;
1170 llvm::SmallVector<mlir::Value> fieldValues;
1171 for (Operation &op :
1172 llvm::make_early_inc_range(classOp.getBodyBlock()->getOperations())) {
1173 if (
auto propAssign = dyn_cast<PropAssignOp>(op)) {
1174 if (
auto blockArg = dyn_cast<BlockArgument>(propAssign.getDest())) {
1176 fieldLocs.push_back(op.getLoc());
1177 fieldValues.push_back(propAssign.getSrc());
1184 if (hasContainingModule) {
1185 BlockArgument argumentValue = classBody->addArgument(
1187 fieldLocs.push_back(argumentValue.getLoc());
1188 fieldValues.push_back(argumentValue);
1191 OpBuilder builder = OpBuilder::atBlockEnd(classOp.getBodyBlock());
1192 classOp.addNewFieldsOp(builder, fieldLocs, fieldValues);
1196 if (!isa<firrtl::ClassLike>(moduleLike.getOperation())) {
1198 moduleLike.erasePorts(portsToErase);
1202 void LowerClassesPass::lowerClassExtern(ClassExternOp classExternOp,
1203 FModuleLike moduleLike) {
1207 BitVector portsToErase(moduleLike.getNumPorts());
1208 Block *classBody = &classExternOp.getRegion().emplaceBlock();
1214 for (
unsigned i = 0, e = moduleLike.getNumPorts(); i < e; ++i) {
1215 auto type = moduleLike.getPortType(i);
1216 if (!isa<PropertyType>(type))
1219 auto loc = moduleLike.getPortLocation(i);
1220 auto direction = moduleLike.getPortDirection(i);
1221 if (direction == Direction::In)
1222 classBody->addArgument(type, loc);
1225 portsToErase.set(i);
1230 if (!isa<firrtl::ClassLike>(moduleLike.getOperation())) {
1232 moduleLike.erasePorts(portsToErase);
1239 firrtl::ObjectOp firrtlObject,
const PathInfoTable &pathInfoTable,
1240 SmallVectorImpl<RtlPortsInfo> &rtlPortsToCreate, std::mutex &intraPassMutex,
1241 SmallVectorImpl<Operation *> &opsToErase) {
1243 auto basePath = firrtlObject->getBlock()->getArgument(0);
1246 auto firrtlClassType = firrtlObject.getType();
1247 auto numElements = firrtlClassType.getNumElements();
1248 llvm::SmallVector<unsigned> argIndexTable;
1252 SmallVector<Value> altBasePaths;
1253 pathInfoTable.collectAltBasePaths(
1254 firrtlObject, firrtlClassType.getNameAttr().getAttr(), altBasePaths);
1257 unsigned nextArgIndex = 1 + altBasePaths.size();
1260 auto direction = firrtlClassType.getElement(i).direction;
1261 if (direction == Direction::In)
1262 argIndexTable[i] = nextArgIndex++;
1268 llvm::SmallVector<Value> args;
1269 args.resize(nextArgIndex);
1273 for (
auto [i, altBasePath] : llvm::enumerate(altBasePaths))
1274 args[1 + i] = altBasePath;
1276 firrtl::PathOp containingModuleRef;
1277 for (
auto *user : llvm::make_early_inc_range(firrtlObject->getUsers())) {
1278 if (
auto subfield = dyn_cast<ObjectSubfieldOp>(user)) {
1279 auto index = subfield.getIndex();
1280 auto direction = firrtlClassType.getElement(index).direction;
1284 if (direction == Direction::Out)
1287 for (
auto *subfieldUser :
1288 llvm::make_early_inc_range(subfield->getUsers())) {
1289 if (
auto propassign = dyn_cast<PropAssignOp>(subfieldUser)) {
1293 auto dst = propassign.getOperand(0);
1294 auto src = propassign.getOperand(1);
1295 if (dst == subfield.getResult()) {
1296 args[argIndexTable[index]] = src;
1297 opsToErase.push_back(propassign);
1300 if (firrtlClassType.getElement(index).name.strref().starts_with(
1301 kContainingModuleName)) {
1302 assert(!containingModuleRef &&
1303 "expected exactly one containingModule");
1304 assert(isa_and_nonnull<firrtl::PathOp>(src.getDefiningOp()) &&
1305 "expected containingModule to be a PathOp");
1306 containingModuleRef = src.getDefiningOp<firrtl::PathOp>();
1312 opsToErase.push_back(subfield);
1318 auto element = firrtlClassType.getElement(i);
1319 if (element.direction == Direction::Out)
1322 auto argIndex = argIndexTable[i];
1323 if (!args[argIndex])
1324 return emitError(firrtlObject.getLoc())
1325 <<
"uninitialized input port " << element.name;
1329 auto className = firrtlObject.getType().getNameAttr();
1333 OpBuilder builder(firrtlObject);
1335 auto object = builder.create<om::ObjectOp>(
1336 firrtlObject.getLoc(), classType, firrtlObject.getClassNameAttr(), args);
1339 if (containingModuleRef) {
1340 std::lock_guard<std::mutex> guard(intraPassMutex);
1341 rtlPortsToCreate.push_back({containingModuleRef, basePath,
object});
1346 firrtlObject.replaceAllUsesWith(
object.getResult());
1349 opsToErase.push_back(firrtlObject);
1356 static LogicalResult
1359 const PathInfoTable &pathInfoTable,
1360 SmallVectorImpl<Operation *> &opsToErase) {
1363 OpBuilder builder(firrtlInstance);
1368 SmallVector<Value> actualParameters;
1370 auto basePath = firrtlInstance->getBlock()->getArgument(0);
1372 auto rebasedPath = builder.create<om::BasePathCreateOp>(
1373 firrtlInstance->getLoc(), basePath, symRef);
1375 actualParameters.push_back(rebasedPath);
1378 pathInfoTable.collectAltBasePaths(
1379 firrtlInstance, firrtlInstance.getModuleNameAttr().getAttr(),
1382 for (
auto result : firrtlInstance.getResults()) {
1384 if (firrtlInstance.getPortDirection(result.getResultNumber()) ==
1389 auto propertyResult = dyn_cast<FIRRTLPropertyValue>(result);
1390 if (!propertyResult)
1396 assert(propertyAssignment &&
"properties require single assignment");
1397 actualParameters.push_back(propertyAssignment.getSrcMutable().get());
1400 opsToErase.push_back(propertyAssignment);
1404 auto referencedModule =
1405 firrtlInstance.getReferencedModule<FModuleLike>(instanceGraph);
1407 StringRef moduleName = referencedModule.getName();
1410 if (
auto externMod = dyn_cast<FExtModuleOp>(referencedModule.getOperation()))
1411 if (
auto defname = externMod.getDefname())
1412 moduleName = defname.value();
1416 builder.getStringAttr(moduleName + kClassNameSuffix));
1422 builder.create<om::ObjectOp>(firrtlInstance.getLoc(), classType,
1423 className.getAttr(), actualParameters);
1428 for (
auto result : firrtlInstance.getResults()) {
1430 if (firrtlInstance.getPortDirection(result.getResultNumber()) !=
1435 if (!isa<PropertyType>(result.getType()))
1440 firrtlInstance.getPortName(result.getResultNumber()))});
1443 auto objectField = builder.create<ObjectFieldOp>(
1444 object.getLoc(), result.getType(), object, objectFieldPath);
1446 result.replaceAllUsesWith(objectField);
1450 opsToErase.push_back(firrtlInstance);
1456 static LogicalResult
1458 SmallVectorImpl<Operation *> &opsToErase) {
1460 BitVector portsToErase(firrtlInstance.getNumResults());
1461 for (
auto result : firrtlInstance.getResults())
1462 if (isa<PropertyType>(result.getType()))
1463 portsToErase.set(result.getResultNumber());
1466 if (portsToErase.none())
1470 OpBuilder builder(firrtlInstance);
1471 InstanceOp newInstance = firrtlInstance.erasePorts(builder, portsToErase);
1480 opsToErase.push_back(firrtlInstance);
1484 static LogicalResult
1486 SmallVectorImpl<Operation *> &opsToErase) {
1487 OpBuilder builder(moduleOp);
1488 for (
auto &op : moduleOp->getRegion(0).getOps()) {
1489 if (
auto objectOp = dyn_cast<firrtl::ObjectOp>(op)) {
1490 assert(0 &&
"should be no objects in modules");
1491 }
else if (
auto instanceOp = dyn_cast<InstanceOp>(op)) {
1501 const LoweringState &state,
const PathInfoTable &pathInfoTable,
1502 SmallVectorImpl<RtlPortsInfo> &rtlPortsToCreate, std::mutex &intraPassMutex,
1503 SmallVectorImpl<Operation *> &opsToErase) {
1504 OpBuilder builder(classOp);
1505 auto &classState = state.classLoweringStateTable.at(classOp);
1506 auto it = classState.paths.begin();
1507 for (
auto &op : classOp->getRegion(0).getOps()) {
1508 if (
auto objectOp = dyn_cast<firrtl::ObjectOp>(op)) {
1510 intraPassMutex, opsToErase)))
1512 }
else if (
auto instanceOp = dyn_cast<InstanceOp>(op)) {
1514 pathInfoTable, opsToErase)))
1522 LogicalResult LowerClassesPass::updateInstances(
1523 Operation *op,
InstanceGraph &instanceGraph,
const LoweringState &state,
1524 const PathInfoTable &pathInfoTable, std::mutex &intraPassMutex) {
1529 SmallVector<Operation *> opsToErase;
1531 TypeSwitch<Operation *, LogicalResult>(op)
1533 .Case([&](FModuleOp moduleOp) {
1538 .Case([&](om::ClassOp classOp) {
1542 classOp, instanceGraph, state, pathInfoTable, rtlPortsToCreate,
1543 intraPassMutex, opsToErase);
1545 .Default([](
auto *op) {
return success(); });
1549 for (
auto *op : opsToErase)
1556 void LowerClassesPass::createAllRtlPorts(
1557 const PathInfoTable &pathInfoTable,
1558 hw::InnerSymbolNamespaceCollection &namespaces,
1560 MLIRContext *ctx = &getContext();
1563 OpBuilder builder = OpBuilder::atBlockEnd(getOperation().
getBodyBlock());
1566 om::ClassOp::buildSimpleClassOp(
1568 {
"ref",
"direction",
"width"}, {
"ref",
"direction",
"width"},
1573 llvm::stable_sort(rtlPortsToCreate, [](
auto lhs,
auto rhs) {
1574 return lhs.object.getClassName() < rhs.object.getClassName();
1578 for (
auto rtlPortToCreate : rtlPortsToCreate)
1579 createRtlPorts(rtlPortToCreate, pathInfoTable, namespaces, hierPathCache,
1587 using OpConversionPattern::OpConversionPattern;
1591 ConversionPatternRewriter &rewriter)
const override {
1592 rewriter.replaceOpWithNewOp<om::ConstantOp>(
1600 using OpConversionPattern::OpConversionPattern;
1604 ConversionPatternRewriter &rewriter)
const override {
1605 rewriter.replaceOpWithNewOp<om::ConstantOp>(
1606 op, rewriter.getBoolAttr(adaptor.getValue()));
1613 using OpConversionPattern::OpConversionPattern;
1617 ConversionPatternRewriter &rewriter)
const override {
1618 rewriter.replaceOpWithNewOp<om::ConstantOp>(op, adaptor.getValue());
1625 using OpConversionPattern::OpConversionPattern;
1629 ConversionPatternRewriter &rewriter)
const override {
1631 rewriter.replaceOpWithNewOp<om::ConstantOp>(
1639 using OpConversionPattern::OpConversionPattern;
1643 ConversionPatternRewriter &rewriter)
const override {
1644 auto listType = getTypeConverter()->convertType<om::ListType>(op.getType());
1647 rewriter.replaceOpWithNewOp<om::ListCreateOp>(op, listType,
1648 adaptor.getElements());
1655 using OpConversionPattern::OpConversionPattern;
1659 ConversionPatternRewriter &rewriter)
const override {
1660 auto listType = getTypeConverter()->convertType<om::ListType>(op.getType());
1663 rewriter.replaceOpWithNewOp<om::ListConcatOp>(op, listType,
1664 adaptor.getSubLists());
1671 using OpConversionPattern::OpConversionPattern;
1675 ConversionPatternRewriter &rewriter)
const override {
1676 rewriter.replaceOpWithNewOp<om::IntegerAddOp>(op, adaptor.getLhs(),
1684 using OpConversionPattern::OpConversionPattern;
1688 ConversionPatternRewriter &rewriter)
const override {
1689 rewriter.replaceOpWithNewOp<om::IntegerMulOp>(op, adaptor.getLhs(),
1697 using OpConversionPattern::OpConversionPattern;
1701 ConversionPatternRewriter &rewriter)
const override {
1702 rewriter.replaceOpWithNewOp<om::IntegerShrOp>(op, adaptor.getLhs(),
1710 using OpConversionPattern::OpConversionPattern;
1714 ConversionPatternRewriter &rewriter)
const override {
1715 rewriter.replaceOpWithNewOp<om::IntegerShlOp>(op, adaptor.getLhs(),
1724 const PathInfoTable &pathInfoTable,
1725 PatternBenefit benefit = 1)
1727 pathInfoTable(pathInfoTable) {}
1731 ConversionPatternRewriter &rewriter)
const override {
1732 auto *context = op->getContext();
1734 auto pathInfoIt = pathInfoTable.table.find(op.getTarget());
1737 auto basePath = op->getBlock()->getArgument(0);
1741 if (pathInfoIt == pathInfoTable.table.end()) {
1742 if (op.getTargetKind() == firrtl::TargetKind::DontTouch)
1743 return emitError(op.getLoc(),
"DontTouch target was deleted");
1744 if (op.getTargetKind() == firrtl::TargetKind::Instance)
1745 return emitError(op.getLoc(),
"Instance target was deleted");
1746 rewriter.replaceOpWithNewOp<om::EmptyPathOp>(op);
1750 auto pathInfo = pathInfoIt->second;
1751 auto symbol = pathInfo.symRef;
1755 om::TargetKind targetKind;
1756 switch (op.getTargetKind()) {
1757 case firrtl::TargetKind::DontTouch:
1758 targetKind = om::TargetKind::DontTouch;
1760 case firrtl::TargetKind::Reference:
1761 targetKind = om::TargetKind::Reference;
1763 case firrtl::TargetKind::Instance:
1764 if (!pathInfo.canBeInstanceTarget)
1765 return emitError(op.getLoc(),
"invalid target for instance path")
1766 .attachNote(pathInfo.loc)
1767 <<
"target not instance or module";
1768 targetKind = om::TargetKind::Instance;
1770 case firrtl::TargetKind::MemberInstance:
1771 case firrtl::TargetKind::MemberReference:
1772 if (pathInfo.canBeInstanceTarget)
1773 targetKind = om::TargetKind::MemberInstance;
1775 targetKind = om::TargetKind::MemberReference;
1781 if (
auto altBasePathModule = pathInfo.altBasePathModule) {
1785 auto parent = op->getParentOfType<om::ClassOp>();
1786 auto parentName = parent.getName();
1787 if (parentName.ends_with(kClassNameSuffix))
1788 parentName = parentName.drop_back(kClassNameSuffix.size());
1789 auto originalParentName =
StringAttr::get(op->getContext(), parentName);
1793 pathInfoTable.getRootsForPassthrough(originalParentName);
1794 assert(!altBasePaths.empty() &&
"expected passthrough base paths");
1797 for (
auto [i, altBasePath] : llvm::enumerate(altBasePaths)) {
1798 if (altBasePathModule == altBasePath) {
1800 auto basePathArg = op->getBlock()->getArgument(1 + i);
1801 assert(isa<om::BasePathType>(basePathArg.getType()) &&
1802 "expected a passthrough base path");
1803 basePath = basePathArg;
1808 rewriter.replaceOpWithNewOp<om::PathCreateOp>(
1818 using OpConversionPattern::OpConversionPattern;
1822 ConversionPatternRewriter &rewriter)
const override {
1823 auto wireValue = dyn_cast<FIRRTLPropertyValue>(wireOp.getResult());
1832 auto regionKindInterface = wireOp->getParentOfType<RegionKindInterface>();
1833 if (!regionKindInterface)
1835 if (regionKindInterface.getRegionKind(0) != RegionKind::Graph)
1842 rewriter.replaceOp(wireOp, propAssign.getSrc());
1845 rewriter.eraseOp(propAssign);
1852 using OpConversionPattern::OpConversionPattern;
1856 ConversionPatternRewriter &rewriter)
const override {
1857 rewriter.replaceOpWithNewOp<AnyCastOp>(op, adaptor.getInput());
1864 using OpConversionPattern::OpConversionPattern;
1867 const TypeConverter &typeConverter, MLIRContext *context,
1868 const DenseMap<StringAttr, firrtl::ClassType> &classTypeTable)
1870 classTypeTable(classTypeTable) {}
1874 ConversionPatternRewriter &rewriter)
const override {
1875 auto omClassType = dyn_cast<om::ClassType>(adaptor.getInput().getType());
1881 auto firrtlClassType =
1882 classTypeTable.lookup(omClassType.getClassName().getAttr());
1883 if (!firrtlClassType)
1886 const auto &element = firrtlClassType.getElement(op.getIndex());
1888 if (element.direction == Direction::In)
1892 auto path = rewriter.getArrayAttr({field});
1893 auto type = typeConverter->convertType(element.type);
1894 rewriter.replaceOpWithNewOp<om::ObjectFieldOp>(op, type, adaptor.getInput(),
1903 using OpConversionPattern::OpConversionPattern;
1907 ConversionPatternRewriter &rewriter)
const override {
1908 rewriter.replaceOpWithNewOp<ClassFieldsOp>(op, adaptor.getOperands());
1914 using OpConversionPattern::OpConversionPattern;
1918 ConversionPatternRewriter &rewriter)
const override {
1921 rewriter.replaceOpWithNewOp<om::ObjectOp>(objectOp, objectOp.getType(),
1922 adaptor.getClassNameAttr(),
1923 adaptor.getActualParams());
1929 TypeConverter typeConverter,
1930 ConversionPatternRewriter &rewriter) {
1931 Block *body = classOp.getBodyBlock();
1932 TypeConverter::SignatureConversion result(body->getNumArguments());
1936 typeConverter.convertSignatureArgs(body->getArgumentTypes(), result)))
1940 if (failed(rewriter.convertRegionTypes(body->getParent(), typeConverter,
1944 rewriter.modifyOpInPlace(classOp, [&]() {
1945 mlir::AttrTypeReplacer replacer;
1946 replacer.addReplacement([&](TypeAttr typeAttr) {
1948 typeConverter.convertType(typeAttr.getValue()));
1950 classOp.replaceFieldTypes(replacer);
1957 using OpConversionPattern::OpConversionPattern;
1961 ConversionPatternRewriter &rewriter)
const override {
1968 using OpConversionPattern::OpConversionPattern;
1972 ConversionPatternRewriter &rewriter)
const override {
1978 using OpConversionPattern::OpConversionPattern;
1982 ConversionPatternRewriter &rewriter)
const override {
1985 auto type = typeConverter->convertType(op.getType());
1989 rewriter.replaceOpWithNewOp<ObjectFieldOp>(op, type, adaptor.getObject(),
1990 adaptor.getFieldPathAttr());
2001 target.addDynamicallyLegalDialect<FIRRTLDialect>(
2002 [](Operation *op) {
return !op->getParentOfType<om::ClassLike>(); });
2005 target.addDynamicallyLegalDialect<OMDialect>([](Operation *op) {
2006 auto containsFIRRTLType = [](Type type) {
2008 .walk([](Type type) {
2009 return failure(isa<FIRRTLDialect>(type.getDialect()));
2013 auto noFIRRTLOperands =
2014 llvm::none_of(op->getOperandTypes(), [&containsFIRRTLType](Type type) {
2015 return containsFIRRTLType(type);
2017 auto noFIRRTLResults =
2018 llvm::none_of(op->getResultTypes(), [&containsFIRRTLType](Type type) {
2019 return containsFIRRTLType(type);
2021 return noFIRRTLOperands && noFIRRTLResults;
2025 target.addDynamicallyLegalOp<om::ClassOp, om::ClassExternOp>(
2026 [](Operation *op) -> std::optional<bool> {
2027 auto classLike = dyn_cast<om::ClassLike>(op);
2029 return std::nullopt;
2030 auto fieldNames = classLike.getFieldNames();
2031 if (!llvm::all_of(fieldNames, [&](
auto field) {
2032 std::optional<Type> type =
2033 classLike.getFieldType(cast<StringAttr>(field));
2034 return type.has_value() && !isa<FIRRTLType>(type.value());
2038 return llvm::none_of(
2039 classLike.getBodyBlock()->getArgumentTypes(),
2040 [](Type type) { return isa<FIRRTLDialect>(type.getDialect()); });
2046 converter.addConversion(
2048 converter.addConversion([](FIntegerType type) {
2056 converter.addConversion([](om::StringType type) {
return type; });
2057 converter.addConversion([](firrtl::StringType type) {
2062 converter.addConversion([](om::PathType type) {
return type; });
2063 converter.addConversion([](om::BasePathType type) {
return type; });
2064 converter.addConversion([](om::FrozenPathType type) {
return type; });
2065 converter.addConversion([](om::FrozenBasePathType type) {
return type; });
2066 converter.addConversion([](firrtl::PathType type) {
2071 converter.addConversion([](om::ClassType type) {
return type; });
2072 converter.addConversion([](firrtl::ClassType type) {
2077 converter.addConversion([](om::AnyType type) {
return type; });
2078 converter.addConversion([](firrtl::AnyRefType type) {
2083 auto convertListType = [&converter](
auto type) -> std::optional<mlir::Type> {
2085 if (isa<om::OMDialect>(type.getElementType().getDialect()))
2087 auto elementType = converter.convertType(type.getElementType());
2093 converter.addConversion(
2094 [convertListType](om::ListType type) -> std::optional<mlir::Type> {
2096 return convertListType(type);
2099 converter.addConversion(
2100 [convertListType](firrtl::ListType type) -> std::optional<mlir::Type> {
2102 return convertListType(type);
2106 converter.addConversion(
2110 converter.addConversion(
2111 [](DoubleType type) {
return FloatType::getF64(type.getContext()); });
2115 converter.addTargetMaterialization(
2116 [](OpBuilder &builder, Type type, ValueRange values, Location loc) {
2117 assert(values.size() == 1);
2118 return builder.create<UnrealizedConversionCastOp>(loc, type, values[0])
2124 converter.addSourceMaterialization(
2125 [](OpBuilder &builder, Type type, ValueRange values, Location loc) {
2126 assert(values.size() == 1);
2127 return builder.create<UnrealizedConversionCastOp>(loc, type, values[0])
2133 RewritePatternSet &
patterns, TypeConverter &converter,
2134 const PathInfoTable &pathInfoTable,
2135 const DenseMap<StringAttr, firrtl::ClassType> &classTypeTable) {
2161 LogicalResult LowerClassesPass::dialectConversion(
2162 Operation *op,
const PathInfoTable &pathInfoTable,
2163 const DenseMap<StringAttr, firrtl::ClassType> &classTypeTable) {
2164 ConversionTarget target(getContext());
2167 TypeConverter typeConverter;
2170 RewritePatternSet
patterns(&getContext());
2174 return applyPartialConversion(op, target, std::move(
patterns));
assert(baseType &&"element must be base type")
MlirType uint64_t numElements
static LogicalResult updateInstancesInModule(FModuleOp moduleOp, InstanceGraph &instanceGraph, SmallVectorImpl< Operation * > &opsToErase)
static void populateConversionTarget(ConversionTarget &target)
static om::ClassLike convertClass(FModuleLike moduleLike, OpBuilder builder, Twine name, ArrayRef< StringRef > formalParamNames, bool hasContainingModule)
static LogicalResult updateInstanceInClass(InstanceOp firrtlInstance, hw::HierPathOp hierPath, InstanceGraph &instanceGraph, const PathInfoTable &pathInfoTable, SmallVectorImpl< Operation * > &opsToErase)
static LogicalResult convertClassLike(om::ClassLike classOp, TypeConverter typeConverter, ConversionPatternRewriter &rewriter)
static void populateTypeConverter(TypeConverter &converter)
static LogicalResult updateInstanceInModule(InstanceOp firrtlInstance, InstanceGraph &instanceGraph, SmallVectorImpl< Operation * > &opsToErase)
static LogicalResult updateObjectInClass(firrtl::ObjectOp firrtlObject, const PathInfoTable &pathInfoTable, SmallVectorImpl< RtlPortsInfo > &rtlPortsToCreate, std::mutex &intraPassMutex, SmallVectorImpl< Operation * > &opsToErase)
void checkAddContainingModulePorts(bool hasContainingModule, OpBuilder builder, SmallVector< Attribute > &fieldNames, SmallVector< NamedAttribute > &fieldTypes)
static om::ClassLike convertExtClass(FModuleLike moduleLike, OpBuilder builder, Twine name, ArrayRef< StringRef > formalParamNames, bool hasContainingModule)
static LogicalResult updateObjectsAndInstancesInClass(om::ClassOp classOp, InstanceGraph &instanceGraph, const LoweringState &state, const PathInfoTable &pathInfoTable, SmallVectorImpl< RtlPortsInfo > &rtlPortsToCreate, std::mutex &intraPassMutex, SmallVectorImpl< Operation * > &opsToErase)
static void populateRewritePatterns(RewritePatternSet &patterns, TypeConverter &converter, const PathInfoTable &pathInfoTable, const DenseMap< StringAttr, firrtl::ClassType > &classTypeTable)
static Block * getBodyBlock(FModuleLike mod)
std::shared_ptr< calyx::CalyxLoweringState > loweringState
This class provides a read-only projection of an annotation.
unsigned getFieldID() const
Get the field id this attribute targets.
AttrClass getMember(StringAttr name) const
Return a member of the annotation.
bool isClass(Args... names) const
Return true if this annotation matches any of the specified class names.
This graph tracks modules and where they are instantiated.
This is a Node in the InstanceGraph.
bool noUses()
Return true if there are no more instances of this module.
auto getModule()
Get the module that this node is tracking.
UseIterator usesBegin()
Iterate the instance records which instantiate this module.
bool hasOneUse()
Return true if this module has exactly one use.
llvm::iterator_range< UseIterator > uses()
virtual void replaceInstance(InstanceOpInterface inst, InstanceOpInterface newInst)
Replaces an instance of a module with another instance.
InstanceGraphNode * lookup(ModuleOpInterface op)
Look up an InstanceGraphNode for a module.
This is an edge in the InstanceGraph.
auto getInstance()
Get the instance-like op that this is tracking.
InstanceGraphNode * getParent() const
Get the module where the instantiation lives.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
hw::InnerRefAttr getInnerRefTo(const hw::InnerSymTarget &target, GetNamespaceCallback getNamespace)
Obtain an inner reference to the target (operation or port), adding an inner symbol as necessary.
PropAssignOp getPropertyAssignment(FIRRTLPropertyValue value)
Return the single assignment to a Property value.
std::unique_ptr< mlir::Pass > createLowerClassesPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
int run(Type[Generator] generator=CppGenerator, cmdline_args=sys.argv)
LogicalResult matchAndRewrite(ObjectAnyRefCastOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(BoolConstantOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(om::ClassExternOp classOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(ClassFieldsOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(om::ClassOp classOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(DoubleConstantOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(FIntegerConstantOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(firrtl::IntegerAddOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(firrtl::IntegerMulOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(firrtl::IntegerShlOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(firrtl::IntegerShrOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(firrtl::ListConcatOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(firrtl::ListCreateOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(ObjectFieldOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(om::ObjectOp objectOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
ObjectSubfieldOpConversion(const TypeConverter &typeConverter, MLIRContext *context, const DenseMap< StringAttr, firrtl::ClassType > &classTypeTable)
const DenseMap< StringAttr, firrtl::ClassType > & classTypeTable
LogicalResult matchAndRewrite(firrtl::ObjectSubfieldOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
PathOpConversion(TypeConverter &typeConverter, MLIRContext *context, const PathInfoTable &pathInfoTable, PatternBenefit benefit=1)
const PathInfoTable & pathInfoTable
LogicalResult matchAndRewrite(firrtl::PathOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(StringConstantOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
LogicalResult matchAndRewrite(WireOp wireOp, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
An annotation target is used to keep track of something that is targeted by an Annotation.
Operation * getOp() const
FModuleLike getModule() const
Get the parent module of the target.
AnnotationSet getAnnotations() const
Get the annotations associated with the target.
A cache of existing HierPathOps, mostly used to facilitate HierPathOp reuse.
hw::HierPathOp getOpFor(ArrayAttr attr)
FlatSymbolRefAttr getRefFor(ArrayAttr attr)
const SymbolTable & getSymbolTable() const
This represents an annotation targeting a specific operation.
Attribute getNLAReference(hw::InnerSymbolNamespace &moduleNamespace) const
This implements an analysis to determine which module owns a given path operation.
This represents an annotation targeting a specific port of a module, memory, or instance.
This holds the name and type that describes the module's ports.