23 #include "mlir/IR/BuiltinOps.h"
24 #include "mlir/IR/IRMapping.h"
25 #include "mlir/IR/PatternMatch.h"
26 #include "mlir/IR/Threading.h"
27 #include "mlir/Pass/Pass.h"
28 #include "mlir/Support/LogicalResult.h"
29 #include "mlir/Transforms/DialectConversion.h"
30 #include "llvm/ADT/DepthFirstIterator.h"
31 #include "llvm/ADT/STLExtras.h"
32 #include "llvm/Support/raw_ostream.h"
36 #define GEN_PASS_DEF_LOWERCLASSES
37 #include "circt/Dialect/FIRRTL/Passes.h.inc"
42 using namespace circt;
49 auto moduleLike = node->
getModule<FModuleLike>();
53 if (isa<firrtl::ClassLike>(moduleLike.getOperation()))
57 if (moduleLike.isPublic())
61 bool hasClassPorts = llvm::any_of(moduleLike.getPorts(), [](
PortInfo port) {
62 return isa<PropertyType>(port.type);
70 for (
auto *instance : *node) {
71 if (
auto op = instance->getInstance<FInstanceLike>())
72 for (
auto result : op->getResults())
73 if (type_isa<PropertyType>(result.getType()))
84 PathInfo(Location loc,
bool canBeInstanceTarget, FlatSymbolRefAttr symRef,
85 StringAttr altBasePathModule)
86 : loc(loc), canBeInstanceTarget(canBeInstanceTarget), symRef(symRef),
87 altBasePathModule(altBasePathModule) {
88 assert(symRef &&
"symRef must not be null");
92 std::optional<Location> loc = std::nullopt;
95 bool canBeInstanceTarget =
false;
98 FlatSymbolRefAttr symRef =
nullptr;
102 StringAttr altBasePathModule =
nullptr;
106 struct PathInfoTable {
109 void addAltBasePathRoot(StringAttr rootModuleName) {
110 altBasePathRoots.insert(rootModuleName);
115 void addAltBasePathPassthrough(StringAttr passthroughModuleName,
116 StringAttr rootModuleName) {
117 auto &rootSequence = altBasePathsPassthroughs[passthroughModuleName];
118 rootSequence.push_back(rootModuleName);
122 llvm::iterator_range<SmallPtrSetImpl<StringAttr>::iterator>
123 getAltBasePathRoots()
const {
124 return llvm::make_range(altBasePathRoots.begin(), altBasePathRoots.end());
129 size_t getNumAltBasePaths(StringAttr passthroughModuleName)
const {
130 return altBasePathsPassthroughs.lookup(passthroughModuleName).size();
135 llvm::iterator_range<const StringAttr *>
136 getRootsForPassthrough(StringAttr passthroughModuleName)
const {
137 auto it = altBasePathsPassthroughs.find(passthroughModuleName);
138 assert(it != altBasePathsPassthroughs.end() &&
139 "expected passthrough module to already exist");
140 return llvm::make_range(it->second.begin(), it->second.end());
145 void collectAltBasePaths(Operation *instance, StringAttr moduleNameAttr,
146 SmallVectorImpl<Value> &result)
const {
147 auto altBasePaths = altBasePathsPassthroughs.lookup(moduleNameAttr);
148 auto parent = instance->getParentOfType<om::ClassOp>();
151 for (
auto [i, altBasePath] : llvm::enumerate(altBasePaths)) {
152 if (parent.getName().starts_with(altBasePath)) {
154 result.push_back(instance->getBlock()->getArgument(0));
158 auto basePath = instance->getBlock()->getArgument(1 + i);
159 assert(isa<om::BasePathType>(basePath.getType()) &&
160 "expected a passthrough base path");
161 result.push_back(basePath);
167 DenseMap<DistinctAttr, PathInfo> table;
172 SmallPtrSet<StringAttr, 16> altBasePathRoots;
176 DenseMap<StringAttr, SmallVector<StringAttr>> altBasePathsPassthroughs;
180 static constexpr StringRef kClassNameSuffix =
"_Class";
191 struct ClassLoweringState {
192 FModuleLike moduleLike;
193 std::vector<hw::HierPathOp> paths;
196 struct LoweringState {
197 PathInfoTable pathInfoTable;
198 DenseMap<om::ClassLike, ClassLoweringState> classLoweringStateTable;
202 struct RtlPortsInfo {
203 firrtl::PathOp containingModuleRef;
208 struct LowerClassesPass
209 :
public circt::firrtl::impl::LowerClassesBase<LowerClassesPass> {
210 void runOnOperation()
override;
214 hw::InnerSymbolNamespaceCollection &namespaces,
216 SymbolTable &symbolTable);
219 bool shouldCreateClass(StringAttr modName);
222 om::ClassLike createClass(FModuleLike moduleLike,
223 const PathInfoTable &pathInfoTable,
224 std::mutex &intraPassMutex);
227 void lowerClassLike(FModuleLike moduleLike, om::ClassLike classLike,
228 const PathInfoTable &pathInfoTable);
229 void lowerClass(om::ClassOp classOp, FModuleLike moduleLike,
230 const PathInfoTable &pathInfoTable);
231 void lowerClassExtern(ClassExternOp classExternOp, FModuleLike moduleLike);
234 LogicalResult updateInstances(Operation *op,
InstanceGraph &instanceGraph,
235 const LoweringState &state,
236 const PathInfoTable &pathInfoTable,
237 std::mutex &intraPassMutex);
240 void createAllRtlPorts(
const PathInfoTable &pathInfoTable,
241 hw::InnerSymbolNamespaceCollection &namespaces,
245 LogicalResult dialectConversion(
246 Operation *op,
const PathInfoTable &pathInfoTable,
247 const DenseMap<StringAttr, firrtl::ClassType> &classTypeTable);
250 DenseMap<StringAttr, bool> shouldCreateClassMemo;
253 SmallVector<RtlPortsInfo> rtlPortsToCreate;
261 hw::InnerSymbolNamespaceCollection &namespaces,
HierPathCache &cache,
262 PathInfoTable &pathInfoTable,
const SymbolTable &symbolTable,
263 const DenseMap<DistinctAttr, FModuleOp> &owningModules);
265 PathTracker(FModuleLike module,
266 hw::InnerSymbolNamespaceCollection &namespaces,
267 InstanceGraph &instanceGraph,
const SymbolTable &symbolTable,
268 const DenseMap<DistinctAttr, FModuleOp> &owningModules)
269 : module(module), moduleNamespace(namespaces[module]),
270 namespaces(namespaces), instanceGraph(instanceGraph),
271 symbolTable(symbolTable), owningModules(owningModules) {}
274 struct PathInfoTableEntry {
277 StringAttr altBasePathModule;
283 LogicalResult runOnModule();
286 FailureOr<AnnotationSet> processPathTrackers(
const AnnoTarget &target);
288 LogicalResult updatePathInfoTable(PathInfoTable &pathInfoTable,
293 FailureOr<bool> getOrComputeNeedsAltBasePath(Location loc,
294 StringAttr moduleName,
295 FModuleOp owningModule,
300 hw::InnerSymbolNamespace &moduleNamespace;
301 hw::InnerSymbolNamespaceCollection &namespaces;
302 DenseMap<std::pair<StringAttr, FModuleOp>,
bool> needsAltBasePathCache;
306 const SymbolTable &symbolTable;
307 const DenseMap<DistinctAttr, FModuleOp> &owningModules;
310 SmallVector<PathInfoTableEntry> entries;
311 SetVector<StringAttr> altBasePathRoots;
316 static constexpr StringRef kContainingModuleName =
"containingModule";
317 static constexpr StringRef kPortsName =
"ports";
318 static constexpr StringRef kRtlPortClassName =
"RtlPort";
320 static Type getRtlPortsType(MLIRContext *context) {
326 static void createRtlPorts(
const RtlPortsInfo &rtlPortToCreate,
327 const PathInfoTable &pathInfoTable,
328 hw::InnerSymbolNamespaceCollection &namespaces,
330 firrtl::PathOp containingModuleRef = rtlPortToCreate.containingModuleRef;
331 Value basePath = rtlPortToCreate.basePath;
332 om::ObjectOp
object = rtlPortToCreate.object;
335 OpBuilder::InsertionGuard guard(builder);
336 builder.setInsertionPoint(
object);
340 FlatSymbolRefAttr containingModulePathRef =
341 pathInfoTable.table.at(containingModuleRef.getTarget()).symRef;
345 hw::HierPathOp containingModulePath =
346 symbolTable.lookup<hw::HierPathOp>(containingModulePathRef.getAttr());
348 assert(containingModulePath.isModule() &&
349 "expected containing module path to target a module");
351 StringAttr moduleName = containingModulePath.leafMod();
353 FModuleLike mod = symbolTable.lookup<FModuleLike>(moduleName);
354 MLIRContext *ctx = mod.getContext();
355 Location loc = mod.getLoc();
363 SmallVector<Value> ports;
364 for (
unsigned i = 0, e = mod.getNumPorts(); i < e; ++i) {
366 auto portType = type_dyn_cast<FIRRTLBaseType>(mod.getPortType(i));
367 if (!portType || portType.getBitWidthOrSentinel() == 0)
376 getInnerRefTo({portTarget.getPortNo(), portTarget.getOp(), 0},
377 [&](FModuleLike m) -> hw::InnerSymbolNamespace & {
378 return namespaces[m];
381 FlatSymbolRefAttr portPathRef =
384 auto portPath = builder.create<om::PathCreateOp>(
391 StringRef portDirectionName =
392 mod.getPortDirection(i) == Direction::Out ?
"Output" :
"Input";
394 auto portDirection = builder.create<om::ConstantOp>(
400 auto portWidth = builder.create<om::ConstantOp>(
404 portType.getBitWidthOrSentinel())));
408 auto portObj = builder.create<om::ObjectOp>(
409 loc, portClassType, portClassName,
410 ArrayRef<Value>{portPath, portDirection, portWidth});
412 ports.push_back(portObj);
417 auto portsList = builder.create<om::ListCreateOp>(
419 getRtlPortsType(builder.getContext()), ports);
421 object.getActualParamsMutable().append({portsList});
428 hw::InnerSymbolNamespaceCollection &namespaces,
430 const SymbolTable &symbolTable,
431 const DenseMap<DistinctAttr, FModuleOp> &owningModules) {
434 for (
auto *node : instanceGraph)
435 if (
auto module = node->
getModule<FModuleLike>())
436 (void)namespaces.get(module);
438 for (
auto *node : instanceGraph)
439 if (
auto module = node->
getModule<FModuleLike>()) {
441 if (isa<firrtl::ClassOp, firrtl::ExtClassOp>(module))
443 PathTracker tracker(module, namespaces, instanceGraph, symbolTable,
445 if (failed(tracker.runOnModule()))
447 if (failed(tracker.updatePathInfoTable(pathInfoTable, cache)))
454 LogicalResult PathTracker::runOnModule() {
455 auto processAndUpdateAnnoTarget = [&](
AnnoTarget target) -> LogicalResult {
456 auto anno = processPathTrackers(target);
459 target.setAnnotations(*anno);
464 if (failed(processAndUpdateAnnoTarget(
OpAnnoTarget(module))))
468 SmallVector<Attribute> portAnnotations;
469 portAnnotations.reserve(module.getNumPorts());
470 for (
unsigned i = 0, e = module.getNumPorts(); i < e; ++i) {
474 portAnnotations.push_back(annos->getArrayAttr());
477 module.setPortAnnotationsAttr(
481 auto result = module.walk([&](hw::InnerSymbolOpInterface op) {
482 if (failed(processAndUpdateAnnoTarget(
OpAnnoTarget(op))))
483 return WalkResult::interrupt();
484 return WalkResult::advance();
487 if (result.wasInterrupted())
495 PathTracker::getOrComputeNeedsAltBasePath(Location loc, StringAttr moduleName,
496 FModuleOp owningModule,
499 auto it = needsAltBasePathCache.find({moduleName, owningModule});
500 if (it != needsAltBasePathCache.end())
502 bool needsAltBasePath =
false;
503 auto *node = instanceGraph.lookup(moduleName);
513 needsAltBasePath =
true;
519 auto diag = mlir::emitError(loc)
520 <<
"unable to uniquely resolve target due "
521 "to multiple instantiation";
522 for (
auto *use : node->
uses())
523 diag.attachNote(use->getInstance().getLoc()) <<
"instance here";
526 node = (*node->
usesBegin())->getParent();
528 needsAltBasePathCache[{moduleName, owningModule}] = needsAltBasePath;
529 return needsAltBasePath;
532 FailureOr<AnnotationSet>
533 PathTracker::processPathTrackers(
const AnnoTarget &target) {
536 auto *op = target.
getOp();
537 annotations.removeAnnotations([&](
Annotation anno) {
543 if (!anno.
isClass(
"circt.tracker"))
547 auto id = anno.
getMember<DistinctAttr>(
"id");
549 op->emitError(
"circt.tracker annotation missing id field");
559 if (
auto portTarget = dyn_cast<PortAnnoTarget>(target)) {
561 getInnerRefTo({portTarget.getPortNo(), portTarget.getOp(), fieldID},
562 [&](FModuleLike module) -> hw::InnerSymbolNamespace & {
563 return moduleNamespace;
565 }
else if (
auto module = dyn_cast<FModuleLike>(op)) {
566 assert(!fieldID &&
"field not valid for modules");
571 [&](FModuleLike module) -> hw::InnerSymbolNamespace & {
572 return moduleNamespace;
577 SmallVector<Attribute> path;
580 path.push_back(targetSym);
582 auto moduleName = target.
getModule().getModuleNameAttr();
585 hw::HierPathOp hierPathOp;
586 if (
auto hierName = anno.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal")) {
588 dyn_cast<hw::HierPathOp>(symbolTable.lookup(hierName.getAttr()));
590 op->emitError(
"annotation does not point at a HierPathOp");
598 auto owningModule = owningModules.lookup(
id);
600 PathInfoTableEntry entry;
604 entries.push_back(entry);
611 auto oldPath = hierPathOp.getNamepath().getValue();
616 bool pathContainsOwningModule =
false;
617 size_t owningModuleIndex = 0;
618 for (
auto [idx, pathFramgent] : llvm::enumerate(oldPath)) {
619 if (
auto innerRef = dyn_cast<hw::InnerRefAttr>(pathFramgent)) {
620 if (innerRef.getModule() == owningModule.getModuleNameAttr()) {
621 pathContainsOwningModule =
true;
622 owningModuleIndex = idx;
624 }
else if (
auto symRef = dyn_cast<FlatSymbolRefAttr>(pathFramgent)) {
625 if (symRef.getAttr() == owningModule.getModuleNameAttr()) {
626 pathContainsOwningModule =
true;
627 owningModuleIndex = idx;
632 if (pathContainsOwningModule) {
634 moduleName = owningModule.getModuleNameAttr();
638 llvm::append_range(path, llvm::reverse(oldPath.drop_back().drop_front(
639 owningModuleIndex)));
642 moduleName = cast<hw::InnerRefAttr>(oldPath.front()).getModule();
645 llvm::append_range(path, llvm::reverse(oldPath.drop_back()));
650 auto needsAltBasePath = getOrComputeNeedsAltBasePath(
651 op->getLoc(), moduleName, owningModule, hierPathOp);
652 if (failed(needsAltBasePath)) {
664 if (!hierPathOp && !needsAltBasePath.value())
682 std::reverse(path.begin(), path.end());
687 StringAttr altBasePathModule;
688 if (*needsAltBasePath) {
690 TypeSwitch<Attribute, StringAttr>(path.front())
691 .Case<FlatSymbolRefAttr>([](
auto a) {
return a.getAttr(); })
692 .Case<hw::InnerRefAttr>([](
auto a) {
return a.getModule(); });
694 altBasePathRoots.insert(altBasePathModule);
698 entries.push_back({op, id, altBasePathModule, pathAttr});
710 LogicalResult PathTracker::updatePathInfoTable(PathInfoTable &pathInfoTable,
712 for (
auto root : altBasePathRoots)
713 pathInfoTable.addAltBasePathRoot(root);
715 for (
const auto &entry : entries) {
717 auto [it, inserted] = pathInfoTable.table.try_emplace(entry.id);
718 auto &pathInfo = it->second;
720 assert(pathInfo.loc.has_value() &&
"all PathInfo should have a Location");
721 auto diag = emitError(pathInfo.loc.value(),
722 "path identifier already found, paths must resolve "
723 "to a unique target");
724 diag.attachNote(entry.op->getLoc()) <<
"other path identifier here";
730 bool canBeInstanceTarget = isa<InstanceOp, FModuleLike>(entry.op);
732 if (entry.pathAttr) {
733 pathInfo = {entry.op->getLoc(), canBeInstanceTarget,
734 cache.
getRefFor(entry.pathAttr), entry.altBasePathModule};
736 pathInfo.loc = entry.op->getLoc();
737 pathInfo.canBeInstanceTarget = canBeInstanceTarget;
749 LogicalResult LowerClassesPass::processPaths(
751 hw::InnerSymbolNamespaceCollection &namespaces,
HierPathCache &cache,
752 PathInfoTable &pathInfoTable, SymbolTable &symbolTable) {
753 auto circuit = getOperation();
757 DenseMap<DistinctAttr, FModuleOp> owningModules;
758 std::vector<Operation *> declarations;
759 auto result = circuit.walk([&](Operation *op) {
760 if (
auto pathOp = dyn_cast<PathOp>(op)) {
762 auto owningModule = owningModuleCache.lookup(pathOp);
765 pathOp->emitError(
"path does not have a single owning module");
766 return WalkResult::interrupt();
768 auto target = pathOp.getTargetAttr();
769 auto [it, inserted] = owningModules.try_emplace(target, owningModule);
772 if (!inserted && it->second != owningModule) {
774 <<
"path reference " << target <<
" has conflicting owning modules "
775 << it->second.getModuleNameAttr() <<
" and "
776 << owningModule.getModuleNameAttr();
777 return WalkResult::interrupt();
780 return WalkResult::advance();
783 if (result.wasInterrupted())
787 pathInfoTable, symbolTable, owningModules)))
792 for (
auto rootModule : pathInfoTable.getAltBasePathRoots()) {
797 auto start = llvm::df_begin(node);
798 auto end = llvm::df_end(node);
808 if (!shouldCreateClass(
809 it->getModule<FModuleLike>().getModuleNameAttr())) {
810 it = it.skipChildren();
815 if (it->begin() == it->end()) {
821 StringAttr passthroughModule = it->getModule().getModuleNameAttr();
822 pathInfoTable.addAltBasePathPassthrough(passthroughModule, rootModule);
832 void LowerClassesPass::runOnOperation() {
833 MLIRContext *ctx = &getContext();
834 auto intraPassMutex = std::mutex();
837 CircuitOp circuit = getOperation();
841 SymbolTable &symbolTable = getAnalysis<SymbolTable>();
843 hw::InnerSymbolNamespaceCollection namespaces;
847 for (
auto *node : instanceGraph)
848 if (
auto moduleLike = node->
getModule<firrtl::FModuleLike>())
849 shouldCreateClassMemo.insert({moduleLike.getModuleNameAttr(),
false});
851 parallelForEach(circuit.getContext(), instanceGraph,
853 if (auto moduleLike = node->getModule<FModuleLike>())
854 shouldCreateClassMemo[moduleLike.getModuleNameAttr()] =
855 shouldCreateClassImpl(node);
859 PathInfoTable pathInfoTable;
860 if (failed(processPaths(instanceGraph, namespaces, cache, pathInfoTable,
869 DenseMap<StringAttr, firrtl::ClassType> classTypeTable;
870 for (
auto *node : instanceGraph) {
871 auto moduleLike = node->
getModule<firrtl::FModuleLike>();
875 if (shouldCreateClass(moduleLike.getModuleNameAttr())) {
876 auto omClass = createClass(moduleLike, pathInfoTable, intraPassMutex);
877 auto &classLoweringState =
loweringState.classLoweringStateTable[omClass];
878 classLoweringState.moduleLike = moduleLike;
885 for (
auto *instance : *node) {
886 auto inst = instance->
getInstance<firrtl::InstanceOp>();
890 auto module = instance->getTarget()->getModule<FModuleLike>();
891 if (module && shouldCreateClass(module.getModuleNameAttr())) {
893 {inst, 0}, [&](FModuleLike module) -> hw::InnerSymbolNamespace & {
894 return namespaces[module];
896 SmallVector<Attribute> path = {targetSym};
898 auto hierPath = cache.
getOpFor(pathAttr);
899 classLoweringState.paths.push_back(hierPath);
904 dyn_cast<firrtl::ClassLike>(moduleLike.getOperation()))
905 classTypeTable[classLike.getNameAttr()] = classLike.getInstanceType();
910 mlir::parallelForEach(ctx,
loweringState.classLoweringStateTable,
911 [
this, &pathInfoTable](
auto &entry) {
912 const auto &[classLike, state] = entry;
913 lowerClassLike(state.moduleLike, classLike,
918 for (
auto &[omClass, state] :
loweringState.classLoweringStateTable) {
919 if (isa<firrtl::ClassLike>(state.moduleLike.getOperation())) {
921 for (
auto *use : llvm::make_early_inc_range(node->
uses()))
923 instanceGraph.erase(node);
924 state.moduleLike.erase();
929 SmallVector<Operation *> objectContainers;
930 for (
auto &op : circuit.getOps())
931 if (isa<FModuleOp, om::ClassLike>(op))
932 objectContainers.push_back(&op);
936 mlir::failableParallelForEach(ctx, objectContainers, [&](
auto *op) {
938 pathInfoTable, intraPassMutex);
940 return signalPassFailure();
943 if (!rtlPortsToCreate.empty())
944 createAllRtlPorts(pathInfoTable, namespaces, cache);
948 mlir::failableParallelForEach(ctx, objectContainers, [&](
auto *op) {
949 return dialectConversion(op, pathInfoTable, classTypeTable);
951 return signalPassFailure();
954 markAnalysesPreserved<InstanceGraph>();
957 rtlPortsToCreate.clear();
961 return std::make_unique<LowerClassesPass>();
965 bool LowerClassesPass::shouldCreateClass(StringAttr modName) {
967 return shouldCreateClassMemo.at(modName);
971 SmallVector<Attribute> &fieldNames,
972 SmallVector<NamedAttribute> &fieldTypes) {
973 if (hasContainingModule) {
974 auto name = builder.getStringAttr(kPortsName);
975 fieldNames.push_back(name);
976 fieldTypes.push_back(NamedAttribute(
977 name,
TypeAttr::get(getRtlPortsType(builder.getContext()))));
983 ArrayRef<StringRef> formalParamNames,
984 bool hasContainingModule) {
985 SmallVector<Attribute> fieldNames;
986 SmallVector<NamedAttribute> fieldTypes;
987 for (
unsigned i = 0, e = moduleLike.getNumPorts(); i < e; ++i) {
988 auto type = moduleLike.getPortType(i);
989 if (!isa<PropertyType>(type))
992 auto direction = moduleLike.getPortDirection(i);
993 if (direction != Direction::In) {
994 auto name = moduleLike.getPortNameAttr(i);
995 fieldNames.push_back(name);
996 fieldTypes.push_back(NamedAttribute(name,
TypeAttr::get(type)));
1001 return builder.create<om::ClassExternOp>(
1002 moduleLike.getLoc(), name, formalParamNames, fieldNames, fieldTypes);
1005 static om::ClassLike
convertClass(FModuleLike moduleLike, OpBuilder builder,
1007 ArrayRef<StringRef> formalParamNames,
1008 bool hasContainingModule) {
1010 SmallVector<Attribute> fieldNames;
1011 SmallVector<NamedAttribute> fieldTypes;
1012 for (
auto op : llvm::make_early_inc_range(
1013 moduleLike->getRegion(0).getOps<PropAssignOp>())) {
1014 auto outputPort = dyn_cast<BlockArgument>(op.getDest());
1018 StringAttr name = moduleLike.getPortNameAttr(outputPort.getArgNumber());
1020 fieldNames.push_back(name);
1021 fieldTypes.push_back(
1022 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) {
1111 SmallVector<Property> inputProperties;
1112 BitVector portsToErase(moduleLike.getNumPorts());
1113 bool hasContainingModule =
false;
1114 for (
auto [index, port] : llvm::enumerate(moduleLike.getPorts())) {
1116 if (!isa<PropertyType>(port.type))
1120 if (port.isInput()) {
1121 inputProperties.push_back({index, port.name, port.type, port.loc});
1124 if (port.name.strref().starts_with(kContainingModuleName))
1125 hasContainingModule =
true;
1129 portsToErase.set(index);
1134 Block *classBody = &classOp->getRegion(0).emplaceBlock();
1138 classBody->addArgument(basePathType, unknownLoc);
1141 size_t nAltBasePaths =
1142 pathInfoTable.getNumAltBasePaths(moduleLike.getModuleNameAttr());
1143 for (
size_t i = 0; i < nAltBasePaths; ++i)
1144 classBody->addArgument(basePathType, unknownLoc);
1146 for (
auto inputProperty : inputProperties) {
1147 BlockArgument parameterValue =
1148 classBody->addArgument(inputProperty.type, inputProperty.loc);
1149 BlockArgument inputValue =
1150 moduleLike->getRegion(0).getArgument(inputProperty.index);
1151 mapping.map(inputValue, parameterValue);
1155 SmallVector<Operation *> opsToErase;
1156 OpBuilder builder = OpBuilder::atBlockBegin(classOp.getBodyBlock());
1157 llvm::SmallVector<mlir::Location> fieldLocs;
1158 llvm::SmallVector<mlir::Value> fieldValues;
1159 for (
auto &op : moduleLike->getRegion(0).getOps()) {
1161 auto propertyOperands = llvm::any_of(op.getOperandTypes(), [](Type type) {
1162 return isa<PropertyType>(type);
1164 bool needsClone =
false;
1165 if (
auto instance = dyn_cast<InstanceOp>(op))
1166 needsClone = shouldCreateClass(instance.getReferencedModuleNameAttr());
1169 auto propertyResults = llvm::any_of(
1170 op.getResultTypes(), [](Type type) { return isa<PropertyType>(type); });
1173 if (!needsClone && !propertyOperands && !propertyResults)
1176 bool isField =
false;
1177 if (
auto propAssign = dyn_cast<PropAssignOp>(op)) {
1178 if (isa<BlockArgument>(propAssign.getDest())) {
1180 fieldLocs.push_back(op.getLoc());
1181 fieldValues.push_back(mapping.lookup(propAssign.getSrc()));
1188 builder.clone(op, mapping);
1192 if (!isa<InstanceOp>(op))
1193 opsToErase.push_back(&op);
1197 if (hasContainingModule) {
1198 BlockArgument argumentValue = classBody->addArgument(
1200 fieldLocs.push_back(argumentValue.getLoc());
1201 fieldValues.push_back(argumentValue);
1204 classOp.addNewFieldsOp(builder, fieldLocs, fieldValues);
1208 if (!isa<firrtl::ClassLike>(moduleLike.getOperation())) {
1210 for (
auto *op : llvm::reverse(opsToErase))
1214 moduleLike.erasePorts(portsToErase);
1218 void LowerClassesPass::lowerClassExtern(ClassExternOp classExternOp,
1219 FModuleLike moduleLike) {
1223 BitVector portsToErase(moduleLike.getNumPorts());
1224 Block *classBody = &classExternOp.getRegion().emplaceBlock();
1230 for (
unsigned i = 0, e = moduleLike.getNumPorts(); i < e; ++i) {
1231 auto type = moduleLike.getPortType(i);
1232 if (!isa<PropertyType>(type))
1235 auto loc = moduleLike.getPortLocation(i);
1236 auto direction = moduleLike.getPortDirection(i);
1237 if (direction == Direction::In)
1238 classBody->addArgument(type, loc);
1241 portsToErase.set(i);
1246 if (!isa<firrtl::ClassLike>(moduleLike.getOperation())) {
1248 moduleLike.erasePorts(portsToErase);
1255 firrtl::ObjectOp firrtlObject,
const PathInfoTable &pathInfoTable,
1256 SmallVectorImpl<RtlPortsInfo> &rtlPortsToCreate, std::mutex &intraPassMutex,
1257 SmallVectorImpl<Operation *> &opsToErase) {
1259 auto basePath = firrtlObject->getBlock()->getArgument(0);
1262 auto firrtlClassType = firrtlObject.getType();
1263 auto numElements = firrtlClassType.getNumElements();
1264 llvm::SmallVector<unsigned> argIndexTable;
1268 SmallVector<Value> altBasePaths;
1269 pathInfoTable.collectAltBasePaths(
1270 firrtlObject, firrtlClassType.getNameAttr().getAttr(), altBasePaths);
1273 unsigned nextArgIndex = 1 + altBasePaths.size();
1276 auto direction = firrtlClassType.getElement(i).direction;
1277 if (direction == Direction::In)
1278 argIndexTable[i] = nextArgIndex++;
1284 llvm::SmallVector<Value> args;
1285 args.resize(nextArgIndex);
1289 for (
auto [i, altBasePath] : llvm::enumerate(altBasePaths))
1290 args[1 + i] = altBasePath;
1292 firrtl::PathOp containingModuleRef;
1293 for (
auto *user : llvm::make_early_inc_range(firrtlObject->getUsers())) {
1294 if (
auto subfield = dyn_cast<ObjectSubfieldOp>(user)) {
1295 auto index = subfield.getIndex();
1296 auto direction = firrtlClassType.getElement(index).direction;
1300 if (direction == Direction::Out)
1303 for (
auto *subfieldUser :
1304 llvm::make_early_inc_range(subfield->getUsers())) {
1305 if (
auto propassign = dyn_cast<PropAssignOp>(subfieldUser)) {
1309 auto dst = propassign.getOperand(0);
1310 auto src = propassign.getOperand(1);
1311 if (dst == subfield.getResult()) {
1312 args[argIndexTable[index]] = src;
1313 opsToErase.push_back(propassign);
1316 if (firrtlClassType.getElement(index).name.strref().starts_with(
1317 kContainingModuleName)) {
1318 assert(!containingModuleRef &&
1319 "expected exactly one containingModule");
1320 assert(isa_and_nonnull<firrtl::PathOp>(src.getDefiningOp()) &&
1321 "expected containingModule to be a PathOp");
1322 containingModuleRef = src.getDefiningOp<firrtl::PathOp>();
1328 opsToErase.push_back(subfield);
1334 auto element = firrtlClassType.getElement(i);
1335 if (element.direction == Direction::Out)
1338 auto argIndex = argIndexTable[i];
1339 if (!args[argIndex])
1340 return emitError(firrtlObject.getLoc())
1341 <<
"uninitialized input port " << element.name;
1345 auto className = firrtlObject.getType().getNameAttr();
1349 OpBuilder builder(firrtlObject);
1351 auto object = builder.create<om::ObjectOp>(
1352 firrtlObject.getLoc(), classType, firrtlObject.getClassNameAttr(), args);
1355 if (containingModuleRef) {
1356 std::lock_guard<std::mutex> guard(intraPassMutex);
1357 rtlPortsToCreate.push_back({containingModuleRef, basePath,
object});
1362 firrtlObject.replaceAllUsesWith(
object.getResult());
1365 opsToErase.push_back(firrtlObject);
1372 static LogicalResult
1375 const PathInfoTable &pathInfoTable,
1376 SmallVectorImpl<Operation *> &opsToErase) {
1379 OpBuilder builder(firrtlInstance);
1384 SmallVector<Value> actualParameters;
1386 auto basePath = firrtlInstance->getBlock()->getArgument(0);
1388 auto rebasedPath = builder.create<om::BasePathCreateOp>(
1389 firrtlInstance->getLoc(), basePath, symRef);
1391 actualParameters.push_back(rebasedPath);
1394 pathInfoTable.collectAltBasePaths(
1395 firrtlInstance, firrtlInstance.getModuleNameAttr().getAttr(),
1398 for (
auto result : firrtlInstance.getResults()) {
1400 if (firrtlInstance.getPortDirection(result.getResultNumber()) ==
1405 auto propertyResult = dyn_cast<FIRRTLPropertyValue>(result);
1406 if (!propertyResult)
1412 assert(propertyAssignment &&
"properties require single assignment");
1413 actualParameters.push_back(propertyAssignment.getSrcMutable().get());
1416 opsToErase.push_back(propertyAssignment);
1420 auto referencedModule =
1421 firrtlInstance.getReferencedModule<FModuleLike>(instanceGraph);
1423 StringRef moduleName = referencedModule.getName();
1426 if (
auto externMod = dyn_cast<FExtModuleOp>(referencedModule.getOperation()))
1427 if (
auto defname = externMod.getDefname())
1428 moduleName = defname.value();
1432 builder.getStringAttr(moduleName + kClassNameSuffix));
1438 builder.create<om::ObjectOp>(firrtlInstance.getLoc(), classType,
1439 className.getAttr(), actualParameters);
1444 for (
auto result : firrtlInstance.getResults()) {
1446 if (firrtlInstance.getPortDirection(result.getResultNumber()) !=
1451 if (!isa<PropertyType>(result.getType()))
1456 firrtlInstance.getPortName(result.getResultNumber()))});
1459 auto objectField = builder.create<ObjectFieldOp>(
1460 object.getLoc(), result.getType(), object, objectFieldPath);
1462 result.replaceAllUsesWith(objectField);
1466 opsToErase.push_back(firrtlInstance);
1472 static LogicalResult
1474 SmallVectorImpl<Operation *> &opsToErase) {
1476 BitVector portsToErase(firrtlInstance.getNumResults());
1477 for (
auto result : firrtlInstance.getResults())
1478 if (isa<PropertyType>(result.getType()))
1479 portsToErase.set(result.getResultNumber());
1482 if (portsToErase.none())
1486 OpBuilder builder(firrtlInstance);
1487 InstanceOp newInstance = firrtlInstance.erasePorts(builder, portsToErase);
1496 opsToErase.push_back(firrtlInstance);
1500 static LogicalResult
1502 SmallVectorImpl<Operation *> &opsToErase) {
1503 OpBuilder builder(moduleOp);
1504 for (
auto &op : moduleOp->getRegion(0).getOps()) {
1505 if (
auto objectOp = dyn_cast<firrtl::ObjectOp>(op)) {
1506 assert(0 &&
"should be no objects in modules");
1507 }
else if (
auto instanceOp = dyn_cast<InstanceOp>(op)) {
1517 const LoweringState &state,
const PathInfoTable &pathInfoTable,
1518 SmallVectorImpl<RtlPortsInfo> &rtlPortsToCreate, std::mutex &intraPassMutex,
1519 SmallVectorImpl<Operation *> &opsToErase) {
1520 OpBuilder builder(classOp);
1521 auto &classState = state.classLoweringStateTable.at(classOp);
1522 auto it = classState.paths.begin();
1523 for (
auto &op : classOp->getRegion(0).getOps()) {
1524 if (
auto objectOp = dyn_cast<firrtl::ObjectOp>(op)) {
1526 intraPassMutex, opsToErase)))
1528 }
else if (
auto instanceOp = dyn_cast<InstanceOp>(op)) {
1530 pathInfoTable, opsToErase)))
1538 LogicalResult LowerClassesPass::updateInstances(
1539 Operation *op,
InstanceGraph &instanceGraph,
const LoweringState &state,
1540 const PathInfoTable &pathInfoTable, std::mutex &intraPassMutex) {
1545 SmallVector<Operation *> opsToErase;
1547 TypeSwitch<Operation *, LogicalResult>(op)
1549 .Case([&](FModuleOp moduleOp) {
1554 .Case([&](om::ClassOp classOp) {
1558 classOp, instanceGraph, state, pathInfoTable, rtlPortsToCreate,
1559 intraPassMutex, opsToErase);
1561 .Default([](
auto *op) {
return success(); });
1565 for (
auto *op : opsToErase)
1572 void LowerClassesPass::createAllRtlPorts(
1573 const PathInfoTable &pathInfoTable,
1574 hw::InnerSymbolNamespaceCollection &namespaces,
1576 MLIRContext *ctx = &getContext();
1579 OpBuilder builder = OpBuilder::atBlockEnd(getOperation().
getBodyBlock());
1582 om::ClassOp::buildSimpleClassOp(
1584 {
"ref",
"direction",
"width"}, {
"ref",
"direction",
"width"},
1589 llvm::stable_sort(rtlPortsToCreate, [](
auto lhs,
auto rhs) {
1590 return lhs.object.getClassName() < rhs.object.getClassName();
1594 for (
auto rtlPortToCreate : rtlPortsToCreate)
1595 createRtlPorts(rtlPortToCreate, pathInfoTable, namespaces, hierPathCache,
1603 using OpConversionPattern::OpConversionPattern;
1607 ConversionPatternRewriter &rewriter)
const override {
1608 rewriter.replaceOpWithNewOp<om::ConstantOp>(
1616 using OpConversionPattern::OpConversionPattern;
1620 ConversionPatternRewriter &rewriter)
const override {
1621 rewriter.replaceOpWithNewOp<om::ConstantOp>(
1622 op, rewriter.getBoolAttr(adaptor.getValue()));
1629 using OpConversionPattern::OpConversionPattern;
1633 ConversionPatternRewriter &rewriter)
const override {
1634 rewriter.replaceOpWithNewOp<om::ConstantOp>(op, adaptor.getValue());
1641 using OpConversionPattern::OpConversionPattern;
1645 ConversionPatternRewriter &rewriter)
const override {
1647 rewriter.replaceOpWithNewOp<om::ConstantOp>(
1655 using OpConversionPattern::OpConversionPattern;
1659 ConversionPatternRewriter &rewriter)
const override {
1660 auto listType = getTypeConverter()->convertType<om::ListType>(op.getType());
1663 rewriter.replaceOpWithNewOp<om::ListCreateOp>(op, listType,
1664 adaptor.getElements());
1671 using OpConversionPattern::OpConversionPattern;
1675 ConversionPatternRewriter &rewriter)
const override {
1676 auto listType = getTypeConverter()->convertType<om::ListType>(op.getType());
1679 rewriter.replaceOpWithNewOp<om::ListConcatOp>(op, listType,
1680 adaptor.getSubLists());
1687 using OpConversionPattern::OpConversionPattern;
1691 ConversionPatternRewriter &rewriter)
const override {
1692 rewriter.replaceOpWithNewOp<om::IntegerAddOp>(op, adaptor.getLhs(),
1700 using OpConversionPattern::OpConversionPattern;
1704 ConversionPatternRewriter &rewriter)
const override {
1705 rewriter.replaceOpWithNewOp<om::IntegerMulOp>(op, adaptor.getLhs(),
1713 using OpConversionPattern::OpConversionPattern;
1717 ConversionPatternRewriter &rewriter)
const override {
1718 rewriter.replaceOpWithNewOp<om::IntegerShrOp>(op, adaptor.getLhs(),
1726 using OpConversionPattern::OpConversionPattern;
1730 ConversionPatternRewriter &rewriter)
const override {
1731 rewriter.replaceOpWithNewOp<om::IntegerShlOp>(op, adaptor.getLhs(),
1740 const PathInfoTable &pathInfoTable,
1741 PatternBenefit benefit = 1)
1743 pathInfoTable(pathInfoTable) {}
1747 ConversionPatternRewriter &rewriter)
const override {
1748 auto *context = op->getContext();
1750 auto pathInfoIt = pathInfoTable.table.find(op.getTarget());
1753 auto basePath = op->getBlock()->getArgument(0);
1757 if (pathInfoIt == pathInfoTable.table.end()) {
1758 if (op.getTargetKind() == firrtl::TargetKind::DontTouch)
1759 return emitError(op.getLoc(),
"DontTouch target was deleted");
1760 if (op.getTargetKind() == firrtl::TargetKind::Instance)
1761 return emitError(op.getLoc(),
"Instance target was deleted");
1762 rewriter.replaceOpWithNewOp<om::EmptyPathOp>(op);
1766 auto pathInfo = pathInfoIt->second;
1767 auto symbol = pathInfo.symRef;
1771 om::TargetKind targetKind;
1772 switch (op.getTargetKind()) {
1773 case firrtl::TargetKind::DontTouch:
1774 targetKind = om::TargetKind::DontTouch;
1776 case firrtl::TargetKind::Reference:
1777 targetKind = om::TargetKind::Reference;
1779 case firrtl::TargetKind::Instance:
1780 if (!pathInfo.canBeInstanceTarget)
1781 return emitError(op.getLoc(),
"invalid target for instance path")
1782 .attachNote(pathInfo.loc)
1783 <<
"target not instance or module";
1784 targetKind = om::TargetKind::Instance;
1786 case firrtl::TargetKind::MemberInstance:
1787 case firrtl::TargetKind::MemberReference:
1788 if (pathInfo.canBeInstanceTarget)
1789 targetKind = om::TargetKind::MemberInstance;
1791 targetKind = om::TargetKind::MemberReference;
1797 if (
auto altBasePathModule = pathInfo.altBasePathModule) {
1801 auto parent = op->getParentOfType<om::ClassOp>();
1802 auto parentName = parent.getName();
1803 if (parentName.ends_with(kClassNameSuffix))
1804 parentName = parentName.drop_back(kClassNameSuffix.size());
1805 auto originalParentName =
StringAttr::get(op->getContext(), parentName);
1809 pathInfoTable.getRootsForPassthrough(originalParentName);
1810 assert(!altBasePaths.empty() &&
"expected passthrough base paths");
1813 for (
auto [i, altBasePath] : llvm::enumerate(altBasePaths)) {
1814 if (altBasePathModule == altBasePath) {
1816 auto basePathArg = op->getBlock()->getArgument(1 + i);
1817 assert(isa<om::BasePathType>(basePathArg.getType()) &&
1818 "expected a passthrough base path");
1819 basePath = basePathArg;
1824 rewriter.replaceOpWithNewOp<om::PathCreateOp>(
1834 using OpConversionPattern::OpConversionPattern;
1838 ConversionPatternRewriter &rewriter)
const override {
1839 auto wireValue = dyn_cast<FIRRTLPropertyValue>(wireOp.getResult());
1848 auto regionKindInterface = wireOp->getParentOfType<RegionKindInterface>();
1849 if (!regionKindInterface)
1851 if (regionKindInterface.getRegionKind(0) != RegionKind::Graph)
1858 rewriter.replaceOp(wireOp, propAssign.getSrc());
1861 rewriter.eraseOp(propAssign);
1868 using OpConversionPattern::OpConversionPattern;
1872 ConversionPatternRewriter &rewriter)
const override {
1873 rewriter.replaceOpWithNewOp<AnyCastOp>(op, adaptor.getInput());
1880 using OpConversionPattern::OpConversionPattern;
1883 const TypeConverter &typeConverter, MLIRContext *context,
1884 const DenseMap<StringAttr, firrtl::ClassType> &classTypeTable)
1886 classTypeTable(classTypeTable) {}
1890 ConversionPatternRewriter &rewriter)
const override {
1891 auto omClassType = dyn_cast<om::ClassType>(adaptor.getInput().getType());
1897 auto firrtlClassType =
1898 classTypeTable.lookup(omClassType.getClassName().getAttr());
1899 if (!firrtlClassType)
1902 const auto &element = firrtlClassType.getElement(op.getIndex());
1904 if (element.direction == Direction::In)
1908 auto path = rewriter.getArrayAttr({field});
1909 auto type = typeConverter->convertType(element.type);
1910 rewriter.replaceOpWithNewOp<om::ObjectFieldOp>(op, type, adaptor.getInput(),
1919 using OpConversionPattern::OpConversionPattern;
1923 ConversionPatternRewriter &rewriter)
const override {
1924 rewriter.replaceOpWithNewOp<ClassFieldsOp>(op, adaptor.getOperands());
1930 using OpConversionPattern::OpConversionPattern;
1934 ConversionPatternRewriter &rewriter)
const override {
1937 rewriter.replaceOpWithNewOp<om::ObjectOp>(objectOp, objectOp.getType(),
1938 adaptor.getClassNameAttr(),
1939 adaptor.getActualParams());
1945 TypeConverter typeConverter,
1946 ConversionPatternRewriter &rewriter) {
1947 Block *body = classOp.getBodyBlock();
1948 TypeConverter::SignatureConversion result(body->getNumArguments());
1952 typeConverter.convertSignatureArgs(body->getArgumentTypes(), result)))
1956 if (failed(rewriter.convertRegionTypes(body->getParent(), typeConverter,
1960 rewriter.modifyOpInPlace(classOp, [&]() {
1961 mlir::AttrTypeReplacer replacer;
1962 replacer.addReplacement([&](TypeAttr typeAttr) {
1964 typeConverter.convertType(typeAttr.getValue()));
1966 classOp.replaceFieldTypes(replacer);
1973 using OpConversionPattern::OpConversionPattern;
1977 ConversionPatternRewriter &rewriter)
const override {
1984 using OpConversionPattern::OpConversionPattern;
1988 ConversionPatternRewriter &rewriter)
const override {
1994 using OpConversionPattern::OpConversionPattern;
1998 ConversionPatternRewriter &rewriter)
const override {
2001 auto type = typeConverter->convertType(op.getType());
2005 rewriter.replaceOpWithNewOp<ObjectFieldOp>(op, type, adaptor.getObject(),
2006 adaptor.getFieldPathAttr());
2017 target.addDynamicallyLegalDialect<FIRRTLDialect>(
2018 [](Operation *op) {
return !op->getParentOfType<om::ClassLike>(); });
2021 target.addDynamicallyLegalDialect<OMDialect>([](Operation *op) {
2022 auto containsFIRRTLType = [](Type type) {
2024 .walk([](Type type) {
2025 return failure(isa<FIRRTLDialect>(type.getDialect()));
2029 auto noFIRRTLOperands =
2030 llvm::none_of(op->getOperandTypes(), [&containsFIRRTLType](Type type) {
2031 return containsFIRRTLType(type);
2033 auto noFIRRTLResults =
2034 llvm::none_of(op->getResultTypes(), [&containsFIRRTLType](Type type) {
2035 return containsFIRRTLType(type);
2037 return noFIRRTLOperands && noFIRRTLResults;
2041 target.addDynamicallyLegalOp<om::ClassOp, om::ClassExternOp>(
2042 [](Operation *op) -> std::optional<bool> {
2043 auto classLike = dyn_cast<om::ClassLike>(op);
2045 return std::nullopt;
2046 auto fieldNames = classLike.getFieldNames();
2047 if (!llvm::all_of(fieldNames, [&](
auto field) {
2048 std::optional<Type> type =
2049 classLike.getFieldType(cast<StringAttr>(field));
2050 return type.has_value() && !isa<FIRRTLType>(type.value());
2054 return llvm::none_of(
2055 classLike.getBodyBlock()->getArgumentTypes(),
2056 [](Type type) { return isa<FIRRTLDialect>(type.getDialect()); });
2062 converter.addConversion(
2064 converter.addConversion([](FIntegerType type) {
2072 converter.addConversion([](om::StringType type) {
return type; });
2073 converter.addConversion([](firrtl::StringType type) {
2078 converter.addConversion([](om::PathType type) {
return type; });
2079 converter.addConversion([](om::BasePathType type) {
return type; });
2080 converter.addConversion([](om::FrozenPathType type) {
return type; });
2081 converter.addConversion([](om::FrozenBasePathType type) {
return type; });
2082 converter.addConversion([](firrtl::PathType type) {
2087 converter.addConversion([](om::ClassType type) {
return type; });
2088 converter.addConversion([](firrtl::ClassType type) {
2093 converter.addConversion([](om::AnyType type) {
return type; });
2094 converter.addConversion([](firrtl::AnyRefType type) {
2099 auto convertListType = [&converter](
auto type) -> std::optional<mlir::Type> {
2101 if (isa<om::OMDialect>(type.getElementType().getDialect()))
2103 auto elementType = converter.convertType(type.getElementType());
2109 converter.addConversion(
2110 [convertListType](om::ListType type) -> std::optional<mlir::Type> {
2112 return convertListType(type);
2115 converter.addConversion(
2116 [convertListType](firrtl::ListType type) -> std::optional<mlir::Type> {
2118 return convertListType(type);
2122 converter.addConversion(
2126 converter.addConversion(
2127 [](DoubleType type) {
return FloatType::getF64(type.getContext()); });
2131 converter.addTargetMaterialization(
2132 [](OpBuilder &builder, Type type, ValueRange values, Location loc) {
2133 assert(values.size() == 1);
2134 return builder.create<UnrealizedConversionCastOp>(loc, type, values[0])
2140 converter.addSourceMaterialization(
2141 [](OpBuilder &builder, Type type, ValueRange values, Location loc) {
2142 assert(values.size() == 1);
2143 return builder.create<UnrealizedConversionCastOp>(loc, type, values[0])
2149 RewritePatternSet &
patterns, TypeConverter &converter,
2150 const PathInfoTable &pathInfoTable,
2151 const DenseMap<StringAttr, firrtl::ClassType> &classTypeTable) {
2177 LogicalResult LowerClassesPass::dialectConversion(
2178 Operation *op,
const PathInfoTable &pathInfoTable,
2179 const DenseMap<StringAttr, firrtl::ClassType> &classTypeTable) {
2180 ConversionTarget target(getContext());
2183 TypeConverter typeConverter;
2186 RewritePatternSet
patterns(&getContext());
2190 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.