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"
34 #define GEN_PASS_DEF_LOWERCLASSES
35 #include "circt/Dialect/FIRRTL/Passes.h.inc"
40 using namespace circt;
47 auto moduleLike = node->
getModule<FModuleLike>();
51 if (isa<firrtl::ClassLike>(moduleLike.getOperation()))
55 if (moduleLike.isPublic())
59 bool hasClassPorts = llvm::any_of(moduleLike.getPorts(), [](
PortInfo port) {
60 return isa<PropertyType>(port.type);
68 for (
auto *instance : *node) {
69 if (
auto op = instance->getInstance<FInstanceLike>())
70 for (
auto result : op->getResults())
71 if (type_isa<PropertyType>(result.getType()))
82 PathInfo(Location loc,
bool canBeInstanceTarget, FlatSymbolRefAttr symRef,
83 StringAttr altBasePathModule)
84 : loc(loc), canBeInstanceTarget(canBeInstanceTarget), symRef(symRef),
85 altBasePathModule(altBasePathModule) {
86 assert(symRef &&
"symRef must not be null");
90 std::optional<Location> loc = std::nullopt;
93 bool canBeInstanceTarget =
false;
96 FlatSymbolRefAttr symRef =
nullptr;
100 StringAttr altBasePathModule =
nullptr;
104 struct PathInfoTable {
107 void addAltBasePathRoot(StringAttr rootModuleName) {
108 altBasePathRoots.insert(rootModuleName);
113 void addAltBasePathPassthrough(StringAttr passthroughModuleName,
114 StringAttr rootModuleName) {
115 auto &rootSequence = altBasePathsPassthroughs[passthroughModuleName];
116 rootSequence.push_back(rootModuleName);
120 llvm::iterator_range<SmallPtrSetImpl<StringAttr>::iterator>
121 getAltBasePathRoots()
const {
122 return llvm::make_range(altBasePathRoots.begin(), altBasePathRoots.end());
127 size_t getNumAltBasePaths(StringAttr passthroughModuleName)
const {
128 return altBasePathsPassthroughs.lookup(passthroughModuleName).size();
133 llvm::iterator_range<const StringAttr *>
134 getRootsForPassthrough(StringAttr passthroughModuleName)
const {
135 auto it = altBasePathsPassthroughs.find(passthroughModuleName);
136 assert(it != altBasePathsPassthroughs.end() &&
137 "expected passthrough module to already exist");
138 return llvm::make_range(it->second.begin(), it->second.end());
143 void collectAltBasePaths(Operation *instance, StringAttr moduleNameAttr,
144 SmallVectorImpl<Value> &result)
const {
145 auto altBasePaths = altBasePathsPassthroughs.lookup(moduleNameAttr);
146 auto parent = instance->getParentOfType<om::ClassOp>();
149 for (
auto [i, altBasePath] : llvm::enumerate(altBasePaths)) {
150 if (parent.getName().starts_with(altBasePath)) {
152 result.push_back(instance->getBlock()->getArgument(0));
156 auto basePath = instance->getBlock()->getArgument(1 + i);
157 assert(isa<om::BasePathType>(basePath.getType()) &&
158 "expected a passthrough base path");
159 result.push_back(basePath);
165 DenseMap<DistinctAttr, PathInfo> table;
170 SmallPtrSet<StringAttr, 16> altBasePathRoots;
174 DenseMap<StringAttr, SmallVector<StringAttr>> altBasePathsPassthroughs;
178 static constexpr StringRef kClassNameSuffix =
"_Class";
189 struct ClassLoweringState {
190 FModuleLike moduleLike;
191 std::vector<hw::HierPathOp> paths;
194 struct LoweringState {
195 PathInfoTable pathInfoTable;
196 DenseMap<om::ClassLike, ClassLoweringState> classLoweringStateTable;
200 struct RtlPortsInfo {
201 firrtl::PathOp containingModuleRef;
206 struct LowerClassesPass
207 :
public circt::firrtl::impl::LowerClassesBase<LowerClassesPass> {
208 void runOnOperation()
override;
212 hw::InnerSymbolNamespaceCollection &namespaces,
214 SymbolTable &symbolTable);
217 bool shouldCreateClass(StringAttr modName);
220 om::ClassLike createClass(FModuleLike moduleLike,
221 const PathInfoTable &pathInfoTable,
222 std::mutex &intraPassMutex);
225 void lowerClassLike(FModuleLike moduleLike, om::ClassLike classLike,
226 const PathInfoTable &pathInfoTable);
227 void lowerClass(om::ClassOp classOp, FModuleLike moduleLike,
228 const PathInfoTable &pathInfoTable);
229 void lowerClassExtern(ClassExternOp classExternOp, FModuleLike moduleLike);
232 LogicalResult updateInstances(Operation *op,
InstanceGraph &instanceGraph,
233 const LoweringState &state,
234 const PathInfoTable &pathInfoTable,
235 std::mutex &intraPassMutex);
238 void createAllRtlPorts(
const PathInfoTable &pathInfoTable,
239 hw::InnerSymbolNamespaceCollection &namespaces,
243 LogicalResult dialectConversion(
244 Operation *op,
const PathInfoTable &pathInfoTable,
245 const DenseMap<StringAttr, firrtl::ClassType> &classTypeTable);
248 DenseMap<StringAttr, bool> shouldCreateClassMemo;
251 SmallVector<RtlPortsInfo> rtlPortsToCreate;
259 hw::InnerSymbolNamespaceCollection &namespaces,
HierPathCache &cache,
260 PathInfoTable &pathInfoTable,
const SymbolTable &symbolTable,
261 const DenseMap<DistinctAttr, FModuleOp> &owningModules);
263 PathTracker(FModuleLike module,
264 hw::InnerSymbolNamespaceCollection &namespaces,
265 InstanceGraph &instanceGraph,
const SymbolTable &symbolTable,
266 const DenseMap<DistinctAttr, FModuleOp> &owningModules)
267 : module(module), moduleNamespace(namespaces[module]),
268 namespaces(namespaces), instanceGraph(instanceGraph),
269 symbolTable(symbolTable), owningModules(owningModules) {}
272 struct PathInfoTableEntry {
275 StringAttr altBasePathModule;
281 LogicalResult runOnModule();
284 FailureOr<AnnotationSet> processPathTrackers(
const AnnoTarget &target);
286 LogicalResult updatePathInfoTable(PathInfoTable &pathInfoTable,
291 FailureOr<bool> getOrComputeNeedsAltBasePath(Location loc,
292 StringAttr moduleName,
293 FModuleOp owningModule,
298 hw::InnerSymbolNamespace &moduleNamespace;
299 hw::InnerSymbolNamespaceCollection &namespaces;
300 DenseMap<std::pair<StringAttr, FModuleOp>,
bool> needsAltBasePathCache;
304 const SymbolTable &symbolTable;
305 const DenseMap<DistinctAttr, FModuleOp> &owningModules;
308 SmallVector<PathInfoTableEntry> entries;
309 SetVector<StringAttr> altBasePathRoots;
314 static constexpr StringRef kContainingModuleName =
"containingModule";
315 static constexpr StringRef kPortsName =
"ports";
316 static constexpr StringRef kRtlPortClassName =
"RtlPort";
318 static Type getRtlPortsType(MLIRContext *context) {
324 static void createRtlPorts(
const RtlPortsInfo &rtlPortToCreate,
325 const PathInfoTable &pathInfoTable,
326 hw::InnerSymbolNamespaceCollection &namespaces,
328 firrtl::PathOp containingModuleRef = rtlPortToCreate.containingModuleRef;
329 Value basePath = rtlPortToCreate.basePath;
330 om::ObjectOp
object = rtlPortToCreate.object;
333 OpBuilder::InsertionGuard guard(builder);
334 builder.setInsertionPoint(
object);
338 FlatSymbolRefAttr containingModulePathRef =
339 pathInfoTable.table.at(containingModuleRef.getTarget()).symRef;
343 hw::HierPathOp containingModulePath =
344 symbolTable.lookup<hw::HierPathOp>(containingModulePathRef.getAttr());
346 assert(containingModulePath.isModule() &&
347 "expected containing module path to target a module");
349 StringAttr moduleName = containingModulePath.leafMod();
351 FModuleLike mod = symbolTable.lookup<FModuleLike>(moduleName);
352 MLIRContext *ctx = mod.getContext();
353 Location loc = mod.getLoc();
361 SmallVector<Value> ports;
362 for (
unsigned i = 0, e = mod.getNumPorts(); i < e; ++i) {
364 auto portType = type_dyn_cast<FIRRTLBaseType>(mod.getPortType(i));
365 if (!portType || portType.getBitWidthOrSentinel() == 0)
374 getInnerRefTo({portTarget.getPortNo(), portTarget.getOp(), 0},
375 [&](FModuleLike m) -> hw::InnerSymbolNamespace & {
376 return namespaces[m];
379 FlatSymbolRefAttr portPathRef =
382 auto portPath = builder.create<om::PathCreateOp>(
389 StringRef portDirectionName =
390 mod.getPortDirection(i) == Direction::Out ?
"Output" :
"Input";
392 auto portDirection = builder.create<om::ConstantOp>(
398 auto portWidth = builder.create<om::ConstantOp>(
402 portType.getBitWidthOrSentinel())));
406 auto portObj = builder.create<om::ObjectOp>(
407 loc, portClassType, portClassName,
408 ArrayRef<Value>{portPath, portDirection, portWidth});
410 ports.push_back(portObj);
415 auto portsList = builder.create<om::ListCreateOp>(
417 getRtlPortsType(builder.getContext()), ports);
419 object.getActualParamsMutable().append({portsList});
426 hw::InnerSymbolNamespaceCollection &namespaces,
428 const SymbolTable &symbolTable,
429 const DenseMap<DistinctAttr, FModuleOp> &owningModules) {
432 for (
auto *node : instanceGraph)
433 if (
auto module = node->
getModule<FModuleLike>())
434 (void)namespaces.get(module);
436 for (
auto *node : instanceGraph)
437 if (
auto module = node->
getModule<FModuleLike>()) {
439 if (isa<firrtl::ClassOp, firrtl::ExtClassOp>(module))
441 PathTracker tracker(module, namespaces, instanceGraph, symbolTable,
443 if (failed(tracker.runOnModule()))
445 if (failed(tracker.updatePathInfoTable(pathInfoTable, cache)))
452 LogicalResult PathTracker::runOnModule() {
453 auto processAndUpdateAnnoTarget = [&](
AnnoTarget target) -> LogicalResult {
454 auto anno = processPathTrackers(target);
457 target.setAnnotations(*anno);
462 if (failed(processAndUpdateAnnoTarget(
OpAnnoTarget(module))))
466 SmallVector<Attribute> portAnnotations;
467 portAnnotations.reserve(module.getNumPorts());
468 for (
unsigned i = 0, e = module.getNumPorts(); i < e; ++i) {
472 portAnnotations.push_back(annos->getArrayAttr());
475 module.setPortAnnotationsAttr(
479 auto result = module.walk([&](hw::InnerSymbolOpInterface op) {
480 if (failed(processAndUpdateAnnoTarget(
OpAnnoTarget(op))))
481 return WalkResult::interrupt();
482 return WalkResult::advance();
485 if (result.wasInterrupted())
493 PathTracker::getOrComputeNeedsAltBasePath(Location loc, StringAttr moduleName,
494 FModuleOp owningModule,
497 auto it = needsAltBasePathCache.find({moduleName, owningModule});
498 if (it != needsAltBasePathCache.end())
500 bool needsAltBasePath =
false;
501 auto *node = instanceGraph.lookup(moduleName);
511 needsAltBasePath =
true;
517 auto diag = mlir::emitError(loc)
518 <<
"unable to uniquely resolve target due "
519 "to multiple instantiation";
520 for (
auto *use : node->
uses())
521 diag.attachNote(use->getInstance().getLoc()) <<
"instance here";
524 node = (*node->
usesBegin())->getParent();
526 needsAltBasePathCache[{moduleName, owningModule}] = needsAltBasePath;
527 return needsAltBasePath;
530 FailureOr<AnnotationSet>
531 PathTracker::processPathTrackers(
const AnnoTarget &target) {
534 auto *op = target.
getOp();
535 annotations.removeAnnotations([&](
Annotation anno) {
541 if (!anno.
isClass(
"circt.tracker"))
545 auto id = anno.
getMember<DistinctAttr>(
"id");
547 op->emitError(
"circt.tracker annotation missing id field");
557 if (
auto portTarget = dyn_cast<PortAnnoTarget>(target)) {
559 getInnerRefTo({portTarget.getPortNo(), portTarget.getOp(), fieldID},
560 [&](FModuleLike module) -> hw::InnerSymbolNamespace & {
561 return moduleNamespace;
563 }
else if (
auto module = dyn_cast<FModuleLike>(op)) {
564 assert(!fieldID &&
"field not valid for modules");
569 [&](FModuleLike module) -> hw::InnerSymbolNamespace & {
570 return moduleNamespace;
575 SmallVector<Attribute> path;
578 path.push_back(targetSym);
580 auto moduleName = target.
getModule().getModuleNameAttr();
583 hw::HierPathOp hierPathOp;
584 if (
auto hierName = anno.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal")) {
586 dyn_cast<hw::HierPathOp>(symbolTable.lookup(hierName.getAttr()));
588 op->emitError(
"annotation does not point at a HierPathOp");
596 auto owningModule = owningModules.lookup(
id);
598 PathInfoTableEntry entry;
602 entries.push_back(entry);
609 auto oldPath = hierPathOp.getNamepath().getValue();
614 bool pathContainsOwningModule =
false;
615 size_t owningModuleIndex = 0;
616 for (
auto [idx, pathFramgent] : llvm::enumerate(oldPath)) {
617 if (
auto innerRef = dyn_cast<hw::InnerRefAttr>(pathFramgent)) {
618 if (innerRef.getModule() == owningModule.getModuleNameAttr()) {
619 pathContainsOwningModule =
true;
620 owningModuleIndex = idx;
622 }
else if (
auto symRef = dyn_cast<FlatSymbolRefAttr>(pathFramgent)) {
623 if (symRef.getAttr() == owningModule.getModuleNameAttr()) {
624 pathContainsOwningModule =
true;
625 owningModuleIndex = idx;
630 if (pathContainsOwningModule) {
632 moduleName = owningModule.getModuleNameAttr();
636 llvm::append_range(path, llvm::reverse(oldPath.drop_back().drop_front(
637 owningModuleIndex)));
640 moduleName = cast<hw::InnerRefAttr>(oldPath.front()).getModule();
643 llvm::append_range(path, llvm::reverse(oldPath.drop_back()));
648 auto needsAltBasePath = getOrComputeNeedsAltBasePath(
649 op->getLoc(), moduleName, owningModule, hierPathOp);
650 if (failed(needsAltBasePath)) {
662 if (!hierPathOp && !needsAltBasePath.value())
680 std::reverse(path.begin(), path.end());
685 StringAttr altBasePathModule;
686 if (*needsAltBasePath) {
688 TypeSwitch<Attribute, StringAttr>(path.front())
689 .Case<FlatSymbolRefAttr>([](
auto a) {
return a.getAttr(); })
690 .Case<hw::InnerRefAttr>([](
auto a) {
return a.getModule(); });
692 altBasePathRoots.insert(altBasePathModule);
696 entries.push_back({op, id, altBasePathModule, pathAttr});
708 LogicalResult PathTracker::updatePathInfoTable(PathInfoTable &pathInfoTable,
710 for (
auto root : altBasePathRoots)
711 pathInfoTable.addAltBasePathRoot(root);
713 for (
const auto &entry : entries) {
715 auto [it, inserted] = pathInfoTable.table.try_emplace(entry.id);
716 auto &pathInfo = it->second;
718 assert(pathInfo.loc.has_value() &&
"all PathInfo should have a Location");
719 auto diag = emitError(pathInfo.loc.value(),
720 "path identifier already found, paths must resolve "
721 "to a unique target");
722 diag.attachNote(entry.op->getLoc()) <<
"other path identifier here";
728 bool canBeInstanceTarget = isa<InstanceOp, FModuleLike>(entry.op);
730 if (entry.pathAttr) {
731 pathInfo = {entry.op->getLoc(), canBeInstanceTarget,
732 cache.
getRefFor(entry.pathAttr), entry.altBasePathModule};
734 pathInfo.loc = entry.op->getLoc();
735 pathInfo.canBeInstanceTarget = canBeInstanceTarget;
747 LogicalResult LowerClassesPass::processPaths(
749 hw::InnerSymbolNamespaceCollection &namespaces,
HierPathCache &cache,
750 PathInfoTable &pathInfoTable, SymbolTable &symbolTable) {
751 auto circuit = getOperation();
755 DenseMap<DistinctAttr, FModuleOp> owningModules;
756 std::vector<Operation *> declarations;
757 auto result = circuit.walk([&](Operation *op) {
758 if (
auto pathOp = dyn_cast<PathOp>(op)) {
760 auto owningModule = owningModuleCache.lookup(pathOp);
763 pathOp->emitError(
"path does not have a single owning module");
764 return WalkResult::interrupt();
766 auto target = pathOp.getTargetAttr();
767 auto [it, inserted] = owningModules.try_emplace(target, owningModule);
770 if (!inserted && it->second != owningModule) {
772 <<
"path reference " << target <<
" has conflicting owning modules "
773 << it->second.getModuleNameAttr() <<
" and "
774 << owningModule.getModuleNameAttr();
775 return WalkResult::interrupt();
778 return WalkResult::advance();
781 if (result.wasInterrupted())
785 pathInfoTable, symbolTable, owningModules)))
790 for (
auto rootModule : pathInfoTable.getAltBasePathRoots()) {
795 auto start = llvm::df_begin(node);
796 auto end = llvm::df_end(node);
806 if (!shouldCreateClass(
807 it->getModule<FModuleLike>().getModuleNameAttr())) {
808 it = it.skipChildren();
813 if (it->begin() == it->end()) {
819 StringAttr passthroughModule = it->getModule().getModuleNameAttr();
820 pathInfoTable.addAltBasePathPassthrough(passthroughModule, rootModule);
830 void LowerClassesPass::runOnOperation() {
831 MLIRContext *ctx = &getContext();
832 auto intraPassMutex = std::mutex();
835 CircuitOp circuit = getOperation();
839 SymbolTable &symbolTable = getAnalysis<SymbolTable>();
841 hw::InnerSymbolNamespaceCollection namespaces;
845 for (
auto *node : instanceGraph)
846 if (
auto moduleLike = node->
getModule<firrtl::FModuleLike>())
847 shouldCreateClassMemo.insert({moduleLike.getModuleNameAttr(),
false});
849 parallelForEach(circuit.getContext(), instanceGraph,
851 if (auto moduleLike = node->getModule<FModuleLike>())
852 shouldCreateClassMemo[moduleLike.getModuleNameAttr()] =
853 shouldCreateClassImpl(node);
857 PathInfoTable pathInfoTable;
858 if (failed(processPaths(instanceGraph, namespaces, cache, pathInfoTable,
867 DenseMap<StringAttr, firrtl::ClassType> classTypeTable;
868 for (
auto *node : instanceGraph) {
869 auto moduleLike = node->
getModule<firrtl::FModuleLike>();
873 if (shouldCreateClass(moduleLike.getModuleNameAttr())) {
874 auto omClass = createClass(moduleLike, pathInfoTable, intraPassMutex);
875 auto &classLoweringState =
loweringState.classLoweringStateTable[omClass];
876 classLoweringState.moduleLike = moduleLike;
883 for (
auto *instance : *node) {
884 auto inst = instance->
getInstance<firrtl::InstanceOp>();
888 auto module = instance->getTarget()->getModule<FModuleLike>();
889 if (module && shouldCreateClass(module.getModuleNameAttr())) {
891 {inst, 0}, [&](FModuleLike module) -> hw::InnerSymbolNamespace & {
892 return namespaces[module];
894 SmallVector<Attribute> path = {targetSym};
896 auto hierPath = cache.
getOpFor(pathAttr);
897 classLoweringState.paths.push_back(hierPath);
902 dyn_cast<firrtl::ClassLike>(moduleLike.getOperation()))
903 classTypeTable[classLike.getNameAttr()] = classLike.getInstanceType();
908 mlir::parallelForEach(ctx,
loweringState.classLoweringStateTable,
909 [
this, &pathInfoTable](
auto &entry) {
910 const auto &[classLike, state] = entry;
911 lowerClassLike(state.moduleLike, classLike,
916 for (
auto &[omClass, state] :
loweringState.classLoweringStateTable) {
917 if (isa<firrtl::ClassLike>(state.moduleLike.getOperation())) {
919 for (
auto *use : llvm::make_early_inc_range(node->
uses()))
921 instanceGraph.erase(node);
922 state.moduleLike.erase();
927 SmallVector<Operation *> objectContainers;
928 for (
auto &op : circuit.getOps())
929 if (isa<FModuleOp, om::ClassLike>(op))
930 objectContainers.push_back(&op);
934 mlir::failableParallelForEach(ctx, objectContainers, [&](
auto *op) {
936 pathInfoTable, intraPassMutex);
938 return signalPassFailure();
941 if (!rtlPortsToCreate.empty())
942 createAllRtlPorts(pathInfoTable, namespaces, cache);
946 mlir::failableParallelForEach(ctx, objectContainers, [&](
auto *op) {
947 return dialectConversion(op, pathInfoTable, classTypeTable);
949 return signalPassFailure();
952 markAnalysesPreserved<InstanceGraph>();
955 rtlPortsToCreate.clear();
959 return std::make_unique<LowerClassesPass>();
963 bool LowerClassesPass::shouldCreateClass(StringAttr modName) {
965 return shouldCreateClassMemo.at(modName);
969 SmallVector<Attribute> &fieldNames,
970 SmallVector<NamedAttribute> &fieldTypes) {
971 if (hasContainingModule) {
972 auto name = builder.getStringAttr(kPortsName);
973 fieldNames.push_back(name);
974 fieldTypes.push_back(NamedAttribute(
975 name,
TypeAttr::get(getRtlPortsType(builder.getContext()))));
981 ArrayRef<StringRef> formalParamNames,
982 bool hasContainingModule) {
983 SmallVector<Attribute> fieldNames;
984 SmallVector<NamedAttribute> fieldTypes;
985 for (
unsigned i = 0, e = moduleLike.getNumPorts(); i < e; ++i) {
986 auto type = moduleLike.getPortType(i);
987 if (!isa<PropertyType>(type))
990 auto direction = moduleLike.getPortDirection(i);
991 if (direction != Direction::In) {
992 auto name = moduleLike.getPortNameAttr(i);
993 fieldNames.push_back(name);
994 fieldTypes.push_back(NamedAttribute(name,
TypeAttr::get(type)));
999 return builder.create<om::ClassExternOp>(
1000 moduleLike.getLoc(), name, formalParamNames, fieldNames, fieldTypes);
1003 static om::ClassLike
convertClass(FModuleLike moduleLike, OpBuilder builder,
1005 ArrayRef<StringRef> formalParamNames,
1006 bool hasContainingModule) {
1008 SmallVector<Attribute> fieldNames;
1009 SmallVector<NamedAttribute> fieldTypes;
1010 for (
auto op : llvm::make_early_inc_range(
1011 moduleLike->getRegion(0).getOps<PropAssignOp>())) {
1012 auto outputPort = dyn_cast<BlockArgument>(op.getDest());
1016 StringAttr name = moduleLike.getPortNameAttr(outputPort.getArgNumber());
1018 fieldNames.push_back(name);
1019 fieldTypes.push_back(
1020 NamedAttribute(name,
TypeAttr::get(op.getSrc().getType())));
1025 return builder.create<om::ClassOp>(moduleLike.getLoc(), name,
1026 formalParamNames, fieldNames, fieldTypes);
1030 om::ClassLike LowerClassesPass::createClass(FModuleLike moduleLike,
1031 const PathInfoTable &pathInfoTable,
1032 std::mutex &intraPassMutex) {
1034 SmallVector<StringRef> formalParamNames;
1036 formalParamNames.emplace_back(
"basepath");
1039 size_t nAltBasePaths =
1040 pathInfoTable.getNumAltBasePaths(moduleLike.getModuleNameAttr());
1041 for (
size_t i = 0; i < nAltBasePaths; ++i)
1043 moduleLike->getContext(),
"alt_basepath_" + llvm::Twine(i)));
1046 bool hasContainingModule =
false;
1047 for (
auto [index, port] : llvm::enumerate(moduleLike.getPorts())) {
1048 if (port.isInput() && isa<PropertyType>(port.type)) {
1049 formalParamNames.push_back(port.name);
1052 if (port.name.strref().starts_with(kContainingModuleName))
1053 hasContainingModule =
true;
1057 OpBuilder builder = OpBuilder::atBlockEnd(getOperation().
getBodyBlock());
1060 if (hasContainingModule)
1061 formalParamNames.push_back(kPortsName);
1064 StringRef className = moduleLike.getName();
1067 if (
auto externMod = dyn_cast<FExtModuleOp>(moduleLike.getOperation()))
1068 if (
auto defname = externMod.getDefname())
1069 className = defname.value();
1074 isa<FModuleOp, FExtModuleOp>(moduleLike) ? kClassNameSuffix :
"";
1077 om::ClassLike loweredClassOp;
1078 if (isa<firrtl::ExtClassOp, firrtl::FExtModuleOp>(
1079 moduleLike.getOperation())) {
1080 loweredClassOp =
convertExtClass(moduleLike, builder, className + suffix,
1081 formalParamNames, hasContainingModule);
1083 loweredClassOp =
convertClass(moduleLike, builder, className + suffix,
1084 formalParamNames, hasContainingModule);
1087 return loweredClassOp;
1090 void LowerClassesPass::lowerClassLike(FModuleLike moduleLike,
1091 om::ClassLike classLike,
1092 const PathInfoTable &pathInfoTable) {
1094 if (
auto classOp = dyn_cast<om::ClassOp>(classLike.getOperation())) {
1095 return lowerClass(classOp, moduleLike, pathInfoTable);
1097 if (
auto classExternOp =
1098 dyn_cast<om::ClassExternOp>(classLike.getOperation())) {
1099 return lowerClassExtern(classExternOp, moduleLike);
1101 llvm_unreachable(
"unhandled class-like op");
1104 void LowerClassesPass::lowerClass(om::ClassOp classOp, FModuleLike moduleLike,
1105 const PathInfoTable &pathInfoTable) {
1107 SmallVector<Property> inputProperties;
1108 BitVector portsToErase(moduleLike.getNumPorts());
1109 bool hasContainingModule =
false;
1110 for (
auto [index, port] : llvm::enumerate(moduleLike.getPorts())) {
1112 if (!isa<PropertyType>(port.type))
1116 if (port.isInput()) {
1117 inputProperties.push_back({index, port.name, port.type, port.loc});
1120 if (port.name.strref().starts_with(kContainingModuleName))
1121 hasContainingModule =
true;
1125 portsToErase.set(index);
1130 Block *moduleBody = &moduleLike->getRegion(0).front();
1131 Block *classBody = &classOp->getRegion(0).emplaceBlock();
1135 classBody->addArgument(basePathType, unknownLoc);
1138 size_t nAltBasePaths =
1139 pathInfoTable.getNumAltBasePaths(moduleLike.getModuleNameAttr());
1140 for (
size_t i = 0; i < nAltBasePaths; ++i)
1141 classBody->addArgument(basePathType, unknownLoc);
1144 for (
auto &op : llvm::make_early_inc_range(llvm::reverse(*moduleBody))) {
1145 if (
auto instance = dyn_cast<InstanceOp>(op)) {
1146 if (!shouldCreateClass(instance.getReferencedModuleNameAttr()))
1148 auto *clone = OpBuilder::atBlockBegin(classBody).clone(op);
1149 for (
auto result : instance.getResults()) {
1150 if (isa<PropertyType>(result.getType()))
1151 result.replaceAllUsesWith(clone->getResult(result.getResultNumber()));
1156 auto isProperty = [](
auto x) {
return isa<PropertyType>(x.getType()); };
1157 if (llvm::any_of(op.getOperands(), isProperty) ||
1158 llvm::any_of(op.getResults(), isProperty))
1159 op.moveBefore(classBody, classBody->begin());
1163 for (
auto input : inputProperties) {
1164 auto arg = classBody->addArgument(input.type, input.loc);
1165 moduleBody->getArgument(input.index).replaceAllUsesWith(arg);
1168 llvm::SmallVector<mlir::Location> fieldLocs;
1169 llvm::SmallVector<mlir::Value> fieldValues;
1170 for (Operation &op :
1171 llvm::make_early_inc_range(classOp.getBodyBlock()->getOperations())) {
1172 if (
auto propAssign = dyn_cast<PropAssignOp>(op)) {
1173 if (
auto blockArg = dyn_cast<BlockArgument>(propAssign.getDest())) {
1175 fieldLocs.push_back(op.getLoc());
1176 fieldValues.push_back(propAssign.getSrc());
1183 if (hasContainingModule) {
1184 BlockArgument argumentValue = classBody->addArgument(
1186 fieldLocs.push_back(argumentValue.getLoc());
1187 fieldValues.push_back(argumentValue);
1190 OpBuilder builder = OpBuilder::atBlockEnd(classOp.getBodyBlock());
1191 classOp.addNewFieldsOp(builder, fieldLocs, fieldValues);
1195 if (!isa<firrtl::ClassLike>(moduleLike.getOperation())) {
1197 moduleLike.erasePorts(portsToErase);
1201 void LowerClassesPass::lowerClassExtern(ClassExternOp classExternOp,
1202 FModuleLike moduleLike) {
1206 BitVector portsToErase(moduleLike.getNumPorts());
1207 Block *classBody = &classExternOp.getRegion().emplaceBlock();
1213 for (
unsigned i = 0, e = moduleLike.getNumPorts(); i < e; ++i) {
1214 auto type = moduleLike.getPortType(i);
1215 if (!isa<PropertyType>(type))
1218 auto loc = moduleLike.getPortLocation(i);
1219 auto direction = moduleLike.getPortDirection(i);
1220 if (direction == Direction::In)
1221 classBody->addArgument(type, loc);
1224 portsToErase.set(i);
1229 if (!isa<firrtl::ClassLike>(moduleLike.getOperation())) {
1231 moduleLike.erasePorts(portsToErase);
1238 firrtl::ObjectOp firrtlObject,
const PathInfoTable &pathInfoTable,
1239 SmallVectorImpl<RtlPortsInfo> &rtlPortsToCreate, std::mutex &intraPassMutex,
1240 SmallVectorImpl<Operation *> &opsToErase) {
1242 auto basePath = firrtlObject->getBlock()->getArgument(0);
1245 auto firrtlClassType = firrtlObject.getType();
1246 auto numElements = firrtlClassType.getNumElements();
1247 llvm::SmallVector<unsigned> argIndexTable;
1251 SmallVector<Value> altBasePaths;
1252 pathInfoTable.collectAltBasePaths(
1253 firrtlObject, firrtlClassType.getNameAttr().getAttr(), altBasePaths);
1256 unsigned nextArgIndex = 1 + altBasePaths.size();
1259 auto direction = firrtlClassType.getElement(i).direction;
1260 if (direction == Direction::In)
1261 argIndexTable[i] = nextArgIndex++;
1267 llvm::SmallVector<Value> args;
1268 args.resize(nextArgIndex);
1272 for (
auto [i, altBasePath] : llvm::enumerate(altBasePaths))
1273 args[1 + i] = altBasePath;
1275 firrtl::PathOp containingModuleRef;
1276 for (
auto *user : llvm::make_early_inc_range(firrtlObject->getUsers())) {
1277 if (
auto subfield = dyn_cast<ObjectSubfieldOp>(user)) {
1278 auto index = subfield.getIndex();
1279 auto direction = firrtlClassType.getElement(index).direction;
1283 if (direction == Direction::Out)
1286 for (
auto *subfieldUser :
1287 llvm::make_early_inc_range(subfield->getUsers())) {
1288 if (
auto propassign = dyn_cast<PropAssignOp>(subfieldUser)) {
1292 auto dst = propassign.getOperand(0);
1293 auto src = propassign.getOperand(1);
1294 if (dst == subfield.getResult()) {
1295 args[argIndexTable[index]] = src;
1296 opsToErase.push_back(propassign);
1299 if (firrtlClassType.getElement(index).name.strref().starts_with(
1300 kContainingModuleName)) {
1301 assert(!containingModuleRef &&
1302 "expected exactly one containingModule");
1303 assert(isa_and_nonnull<firrtl::PathOp>(src.getDefiningOp()) &&
1304 "expected containingModule to be a PathOp");
1305 containingModuleRef = src.getDefiningOp<firrtl::PathOp>();
1311 opsToErase.push_back(subfield);
1317 auto element = firrtlClassType.getElement(i);
1318 if (element.direction == Direction::Out)
1321 auto argIndex = argIndexTable[i];
1322 if (!args[argIndex])
1323 return emitError(firrtlObject.getLoc())
1324 <<
"uninitialized input port " << element.name;
1328 auto className = firrtlObject.getType().getNameAttr();
1332 OpBuilder builder(firrtlObject);
1334 auto object = builder.create<om::ObjectOp>(
1335 firrtlObject.getLoc(), classType, firrtlObject.getClassNameAttr(), args);
1338 if (containingModuleRef) {
1339 std::lock_guard<std::mutex> guard(intraPassMutex);
1340 rtlPortsToCreate.push_back({containingModuleRef, basePath,
object});
1345 firrtlObject.replaceAllUsesWith(
object.getResult());
1348 opsToErase.push_back(firrtlObject);
1355 static LogicalResult
1358 const PathInfoTable &pathInfoTable,
1359 SmallVectorImpl<Operation *> &opsToErase) {
1362 OpBuilder builder(firrtlInstance);
1367 SmallVector<Value> actualParameters;
1369 auto basePath = firrtlInstance->getBlock()->getArgument(0);
1371 auto rebasedPath = builder.create<om::BasePathCreateOp>(
1372 firrtlInstance->getLoc(), basePath, symRef);
1374 actualParameters.push_back(rebasedPath);
1377 pathInfoTable.collectAltBasePaths(
1378 firrtlInstance, firrtlInstance.getModuleNameAttr().getAttr(),
1381 for (
auto result : firrtlInstance.getResults()) {
1383 if (firrtlInstance.getPortDirection(result.getResultNumber()) ==
1388 auto propertyResult = dyn_cast<FIRRTLPropertyValue>(result);
1389 if (!propertyResult)
1395 assert(propertyAssignment &&
"properties require single assignment");
1396 actualParameters.push_back(propertyAssignment.getSrcMutable().get());
1399 opsToErase.push_back(propertyAssignment);
1403 auto referencedModule =
1404 firrtlInstance.getReferencedModule<FModuleLike>(instanceGraph);
1406 StringRef moduleName = referencedModule.getName();
1409 if (
auto externMod = dyn_cast<FExtModuleOp>(referencedModule.getOperation()))
1410 if (
auto defname = externMod.getDefname())
1411 moduleName = defname.value();
1415 builder.getStringAttr(moduleName + kClassNameSuffix));
1421 builder.create<om::ObjectOp>(firrtlInstance.getLoc(), classType,
1422 className.getAttr(), actualParameters);
1427 for (
auto result : firrtlInstance.getResults()) {
1429 if (firrtlInstance.getPortDirection(result.getResultNumber()) !=
1434 if (!isa<PropertyType>(result.getType()))
1439 firrtlInstance.getPortName(result.getResultNumber()))});
1442 auto objectField = builder.create<ObjectFieldOp>(
1443 object.getLoc(), result.getType(), object, objectFieldPath);
1445 result.replaceAllUsesWith(objectField);
1449 opsToErase.push_back(firrtlInstance);
1455 static LogicalResult
1457 SmallVectorImpl<Operation *> &opsToErase) {
1459 BitVector portsToErase(firrtlInstance.getNumResults());
1460 for (
auto result : firrtlInstance.getResults())
1461 if (isa<PropertyType>(result.getType()))
1462 portsToErase.set(result.getResultNumber());
1465 if (portsToErase.none())
1469 OpBuilder builder(firrtlInstance);
1470 InstanceOp newInstance = firrtlInstance.erasePorts(builder, portsToErase);
1479 opsToErase.push_back(firrtlInstance);
1483 static LogicalResult
1485 SmallVectorImpl<Operation *> &opsToErase) {
1486 OpBuilder builder(moduleOp);
1487 for (
auto &op : moduleOp->getRegion(0).getOps()) {
1488 if (
auto objectOp = dyn_cast<firrtl::ObjectOp>(op)) {
1489 assert(0 &&
"should be no objects in modules");
1490 }
else if (
auto instanceOp = dyn_cast<InstanceOp>(op)) {
1500 const LoweringState &state,
const PathInfoTable &pathInfoTable,
1501 SmallVectorImpl<RtlPortsInfo> &rtlPortsToCreate, std::mutex &intraPassMutex,
1502 SmallVectorImpl<Operation *> &opsToErase) {
1503 OpBuilder builder(classOp);
1504 auto &classState = state.classLoweringStateTable.at(classOp);
1505 auto it = classState.paths.begin();
1506 for (
auto &op : classOp->getRegion(0).getOps()) {
1507 if (
auto objectOp = dyn_cast<firrtl::ObjectOp>(op)) {
1509 intraPassMutex, opsToErase)))
1511 }
else if (
auto instanceOp = dyn_cast<InstanceOp>(op)) {
1513 pathInfoTable, opsToErase)))
1521 LogicalResult LowerClassesPass::updateInstances(
1522 Operation *op,
InstanceGraph &instanceGraph,
const LoweringState &state,
1523 const PathInfoTable &pathInfoTable, std::mutex &intraPassMutex) {
1528 SmallVector<Operation *> opsToErase;
1530 TypeSwitch<Operation *, LogicalResult>(op)
1532 .Case([&](FModuleOp moduleOp) {
1537 .Case([&](om::ClassOp classOp) {
1541 classOp, instanceGraph, state, pathInfoTable, rtlPortsToCreate,
1542 intraPassMutex, opsToErase);
1544 .Default([](
auto *op) {
return success(); });
1548 for (
auto *op : opsToErase)
1555 void LowerClassesPass::createAllRtlPorts(
1556 const PathInfoTable &pathInfoTable,
1557 hw::InnerSymbolNamespaceCollection &namespaces,
1559 MLIRContext *ctx = &getContext();
1562 OpBuilder builder = OpBuilder::atBlockEnd(getOperation().
getBodyBlock());
1565 om::ClassOp::buildSimpleClassOp(
1567 {
"ref",
"direction",
"width"}, {
"ref",
"direction",
"width"},
1572 llvm::stable_sort(rtlPortsToCreate, [](
auto lhs,
auto rhs) {
1573 return lhs.object.getClassName() < rhs.object.getClassName();
1577 for (
auto rtlPortToCreate : rtlPortsToCreate)
1578 createRtlPorts(rtlPortToCreate, pathInfoTable, namespaces, hierPathCache,
1586 using OpConversionPattern::OpConversionPattern;
1590 ConversionPatternRewriter &rewriter)
const override {
1591 rewriter.replaceOpWithNewOp<om::ConstantOp>(
1599 using OpConversionPattern::OpConversionPattern;
1603 ConversionPatternRewriter &rewriter)
const override {
1604 rewriter.replaceOpWithNewOp<om::ConstantOp>(
1605 op, rewriter.getBoolAttr(adaptor.getValue()));
1612 using OpConversionPattern::OpConversionPattern;
1616 ConversionPatternRewriter &rewriter)
const override {
1617 rewriter.replaceOpWithNewOp<om::ConstantOp>(op, adaptor.getValue());
1624 using OpConversionPattern::OpConversionPattern;
1628 ConversionPatternRewriter &rewriter)
const override {
1630 rewriter.replaceOpWithNewOp<om::ConstantOp>(
1638 using OpConversionPattern::OpConversionPattern;
1642 ConversionPatternRewriter &rewriter)
const override {
1643 auto listType = getTypeConverter()->convertType<om::ListType>(op.getType());
1646 rewriter.replaceOpWithNewOp<om::ListCreateOp>(op, listType,
1647 adaptor.getElements());
1654 using OpConversionPattern::OpConversionPattern;
1658 ConversionPatternRewriter &rewriter)
const override {
1659 auto listType = getTypeConverter()->convertType<om::ListType>(op.getType());
1662 rewriter.replaceOpWithNewOp<om::ListConcatOp>(op, listType,
1663 adaptor.getSubLists());
1670 using OpConversionPattern::OpConversionPattern;
1674 ConversionPatternRewriter &rewriter)
const override {
1675 rewriter.replaceOpWithNewOp<om::IntegerAddOp>(op, adaptor.getLhs(),
1683 using OpConversionPattern::OpConversionPattern;
1687 ConversionPatternRewriter &rewriter)
const override {
1688 rewriter.replaceOpWithNewOp<om::IntegerMulOp>(op, adaptor.getLhs(),
1696 using OpConversionPattern::OpConversionPattern;
1700 ConversionPatternRewriter &rewriter)
const override {
1701 rewriter.replaceOpWithNewOp<om::IntegerShrOp>(op, adaptor.getLhs(),
1709 using OpConversionPattern::OpConversionPattern;
1713 ConversionPatternRewriter &rewriter)
const override {
1714 rewriter.replaceOpWithNewOp<om::IntegerShlOp>(op, adaptor.getLhs(),
1723 const PathInfoTable &pathInfoTable,
1724 PatternBenefit benefit = 1)
1726 pathInfoTable(pathInfoTable) {}
1730 ConversionPatternRewriter &rewriter)
const override {
1731 auto *context = op->getContext();
1733 auto pathInfoIt = pathInfoTable.table.find(op.getTarget());
1736 auto basePath = op->getBlock()->getArgument(0);
1740 if (pathInfoIt == pathInfoTable.table.end()) {
1741 if (op.getTargetKind() == firrtl::TargetKind::DontTouch)
1742 return emitError(op.getLoc(),
"DontTouch target was deleted");
1743 if (op.getTargetKind() == firrtl::TargetKind::Instance)
1744 return emitError(op.getLoc(),
"Instance target was deleted");
1745 rewriter.replaceOpWithNewOp<om::EmptyPathOp>(op);
1749 auto pathInfo = pathInfoIt->second;
1750 auto symbol = pathInfo.symRef;
1754 om::TargetKind targetKind;
1755 switch (op.getTargetKind()) {
1756 case firrtl::TargetKind::DontTouch:
1757 targetKind = om::TargetKind::DontTouch;
1759 case firrtl::TargetKind::Reference:
1760 targetKind = om::TargetKind::Reference;
1762 case firrtl::TargetKind::Instance:
1763 if (!pathInfo.canBeInstanceTarget)
1764 return emitError(op.getLoc(),
"invalid target for instance path")
1765 .attachNote(pathInfo.loc)
1766 <<
"target not instance or module";
1767 targetKind = om::TargetKind::Instance;
1769 case firrtl::TargetKind::MemberInstance:
1770 case firrtl::TargetKind::MemberReference:
1771 if (pathInfo.canBeInstanceTarget)
1772 targetKind = om::TargetKind::MemberInstance;
1774 targetKind = om::TargetKind::MemberReference;
1780 if (
auto altBasePathModule = pathInfo.altBasePathModule) {
1784 auto parent = op->getParentOfType<om::ClassOp>();
1785 auto parentName = parent.getName();
1786 if (parentName.ends_with(kClassNameSuffix))
1787 parentName = parentName.drop_back(kClassNameSuffix.size());
1788 auto originalParentName =
StringAttr::get(op->getContext(), parentName);
1792 pathInfoTable.getRootsForPassthrough(originalParentName);
1793 assert(!altBasePaths.empty() &&
"expected passthrough base paths");
1796 for (
auto [i, altBasePath] : llvm::enumerate(altBasePaths)) {
1797 if (altBasePathModule == altBasePath) {
1799 auto basePathArg = op->getBlock()->getArgument(1 + i);
1800 assert(isa<om::BasePathType>(basePathArg.getType()) &&
1801 "expected a passthrough base path");
1802 basePath = basePathArg;
1807 rewriter.replaceOpWithNewOp<om::PathCreateOp>(
1817 using OpConversionPattern::OpConversionPattern;
1821 ConversionPatternRewriter &rewriter)
const override {
1822 auto wireValue = dyn_cast<FIRRTLPropertyValue>(wireOp.getResult());
1831 auto regionKindInterface = wireOp->getParentOfType<RegionKindInterface>();
1832 if (!regionKindInterface)
1834 if (regionKindInterface.getRegionKind(0) != RegionKind::Graph)
1841 rewriter.replaceOp(wireOp, propAssign.getSrc());
1844 rewriter.eraseOp(propAssign);
1851 using OpConversionPattern::OpConversionPattern;
1855 ConversionPatternRewriter &rewriter)
const override {
1856 rewriter.replaceOpWithNewOp<AnyCastOp>(op, adaptor.getInput());
1863 using OpConversionPattern::OpConversionPattern;
1866 const TypeConverter &typeConverter, MLIRContext *context,
1867 const DenseMap<StringAttr, firrtl::ClassType> &classTypeTable)
1869 classTypeTable(classTypeTable) {}
1873 ConversionPatternRewriter &rewriter)
const override {
1874 auto omClassType = dyn_cast<om::ClassType>(adaptor.getInput().getType());
1880 auto firrtlClassType =
1881 classTypeTable.lookup(omClassType.getClassName().getAttr());
1882 if (!firrtlClassType)
1885 const auto &element = firrtlClassType.getElement(op.getIndex());
1887 if (element.direction == Direction::In)
1891 auto path = rewriter.getArrayAttr({field});
1892 auto type = typeConverter->convertType(element.type);
1893 rewriter.replaceOpWithNewOp<om::ObjectFieldOp>(op, type, adaptor.getInput(),
1902 using OpConversionPattern::OpConversionPattern;
1906 ConversionPatternRewriter &rewriter)
const override {
1907 rewriter.replaceOpWithNewOp<ClassFieldsOp>(op, adaptor.getOperands());
1913 using OpConversionPattern::OpConversionPattern;
1917 ConversionPatternRewriter &rewriter)
const override {
1920 rewriter.replaceOpWithNewOp<om::ObjectOp>(objectOp, objectOp.getType(),
1921 adaptor.getClassNameAttr(),
1922 adaptor.getActualParams());
1928 TypeConverter typeConverter,
1929 ConversionPatternRewriter &rewriter) {
1930 Block *body = classOp.getBodyBlock();
1931 TypeConverter::SignatureConversion result(body->getNumArguments());
1935 typeConverter.convertSignatureArgs(body->getArgumentTypes(), result)))
1939 if (failed(rewriter.convertRegionTypes(body->getParent(), typeConverter,
1943 rewriter.modifyOpInPlace(classOp, [&]() {
1944 mlir::AttrTypeReplacer replacer;
1945 replacer.addReplacement([&](TypeAttr typeAttr) {
1947 typeConverter.convertType(typeAttr.getValue()));
1949 classOp.replaceFieldTypes(replacer);
1956 using OpConversionPattern::OpConversionPattern;
1960 ConversionPatternRewriter &rewriter)
const override {
1967 using OpConversionPattern::OpConversionPattern;
1971 ConversionPatternRewriter &rewriter)
const override {
1977 using OpConversionPattern::OpConversionPattern;
1981 ConversionPatternRewriter &rewriter)
const override {
1984 auto type = typeConverter->convertType(op.getType());
1988 rewriter.replaceOpWithNewOp<ObjectFieldOp>(op, type, adaptor.getObject(),
1989 adaptor.getFieldPathAttr());
2000 target.addDynamicallyLegalDialect<FIRRTLDialect>(
2001 [](Operation *op) {
return !op->getParentOfType<om::ClassLike>(); });
2004 target.addDynamicallyLegalDialect<OMDialect>([](Operation *op) {
2005 auto containsFIRRTLType = [](Type type) {
2007 .walk([](Type type) {
2008 return failure(isa<FIRRTLDialect>(type.getDialect()));
2012 auto noFIRRTLOperands =
2013 llvm::none_of(op->getOperandTypes(), [&containsFIRRTLType](Type type) {
2014 return containsFIRRTLType(type);
2016 auto noFIRRTLResults =
2017 llvm::none_of(op->getResultTypes(), [&containsFIRRTLType](Type type) {
2018 return containsFIRRTLType(type);
2020 return noFIRRTLOperands && noFIRRTLResults;
2024 target.addDynamicallyLegalOp<om::ClassOp, om::ClassExternOp>(
2025 [](Operation *op) -> std::optional<bool> {
2026 auto classLike = dyn_cast<om::ClassLike>(op);
2028 return std::nullopt;
2029 auto fieldNames = classLike.getFieldNames();
2030 if (!llvm::all_of(fieldNames, [&](
auto field) {
2031 std::optional<Type> type =
2032 classLike.getFieldType(cast<StringAttr>(field));
2033 return type.has_value() && !isa<FIRRTLType>(type.value());
2037 return llvm::none_of(
2038 classLike.getBodyBlock()->getArgumentTypes(),
2039 [](Type type) { return isa<FIRRTLDialect>(type.getDialect()); });
2045 converter.addConversion(
2047 converter.addConversion([](FIntegerType type) {
2055 converter.addConversion([](om::StringType type) {
return type; });
2056 converter.addConversion([](firrtl::StringType type) {
2061 converter.addConversion([](om::PathType type) {
return type; });
2062 converter.addConversion([](om::BasePathType type) {
return type; });
2063 converter.addConversion([](om::FrozenPathType type) {
return type; });
2064 converter.addConversion([](om::FrozenBasePathType type) {
return type; });
2065 converter.addConversion([](firrtl::PathType type) {
2070 converter.addConversion([](om::ClassType type) {
return type; });
2071 converter.addConversion([](firrtl::ClassType type) {
2076 converter.addConversion([](om::AnyType type) {
return type; });
2077 converter.addConversion([](firrtl::AnyRefType type) {
2082 auto convertListType = [&converter](
auto type) -> std::optional<mlir::Type> {
2084 if (isa<om::OMDialect>(type.getElementType().getDialect()))
2086 auto elementType = converter.convertType(type.getElementType());
2092 converter.addConversion(
2093 [convertListType](om::ListType type) -> std::optional<mlir::Type> {
2095 return convertListType(type);
2098 converter.addConversion(
2099 [convertListType](firrtl::ListType type) -> std::optional<mlir::Type> {
2101 return convertListType(type);
2105 converter.addConversion(
2109 converter.addConversion(
2110 [](DoubleType type) {
return FloatType::getF64(type.getContext()); });
2114 converter.addTargetMaterialization(
2115 [](OpBuilder &builder, Type type, ValueRange values, Location loc) {
2116 assert(values.size() == 1);
2117 return builder.create<UnrealizedConversionCastOp>(loc, type, values[0])
2123 converter.addSourceMaterialization(
2124 [](OpBuilder &builder, Type type, ValueRange values, Location loc) {
2125 assert(values.size() == 1);
2126 return builder.create<UnrealizedConversionCastOp>(loc, type, values[0])
2132 RewritePatternSet &
patterns, TypeConverter &converter,
2133 const PathInfoTable &pathInfoTable,
2134 const DenseMap<StringAttr, firrtl::ClassType> &classTypeTable) {
2160 LogicalResult LowerClassesPass::dialectConversion(
2161 Operation *op,
const PathInfoTable &pathInfoTable,
2162 const DenseMap<StringAttr, firrtl::ClassType> &classTypeTable) {
2163 ConversionTarget target(getContext());
2166 TypeConverter typeConverter;
2169 RewritePatternSet
patterns(&getContext());
2173 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.