@@ -352,6 +352,67 @@ void solve(Term *lhs, Term *rhs) {
352352
353353} // namespace
354354
355+ // ====--------------------------------------------------------------------------
356+ // CheckModuleDomains
357+ // ====--------------------------------------------------------------------------
358+
359+ // / Check that a module has complete domain information.
360+ static LogicalResult checkModuleDomains (GlobalState &globals,
361+ FModuleLike module ) {
362+ auto numDomains = globals.circuitInfo .getNumDomains ();
363+ auto domainInfo = module .getDomainInfoAttr ();
364+ DenseMap<unsigned , unsigned > typeIDTable;
365+ for (size_t i = 0 , e = module .getNumPorts (); i < e; ++i) {
366+ auto type = module .getPortType (i);
367+
368+ if (isa<DomainType>(type)) {
369+ auto typeID = globals.circuitInfo .getDomainTypeID (domainInfo, i);
370+ typeIDTable[i] = typeID;
371+ continue ;
372+ }
373+
374+ if (auto baseType = type_dyn_cast<FIRRTLBaseType>(type)) {
375+ SmallVector<IntegerAttr> associations (numDomains);
376+ auto domains = getPortDomainAssociation (domainInfo, i);
377+ for (auto index : domains) {
378+ auto typeID = typeIDTable[index.getUInt ()];
379+ auto &entry = associations[typeID];
380+ if (entry && entry != index) {
381+ auto domainName = globals.circuitInfo .getDomain (typeID).getNameAttr ();
382+ auto portName = module .getPortNameAttr (i);
383+ auto diag = emitError (module .getPortLocation (i))
384+ << " ambiguous " << domainName << " association for port "
385+ << portName;
386+
387+ auto d1Loc = module .getPortLocation (entry.getUInt ());
388+ auto d1Name = module .getPortNameAttr (entry.getUInt ());
389+ diag.attachNote (d1Loc)
390+ << " associated with " << domainName << " port " << d1Name;
391+
392+ auto d2Loc = module .getPortLocation (index.getUInt ());
393+ auto d2Name = module .getPortNameAttr (index.getUInt ());
394+ diag.attachNote (d2Loc)
395+ << " associated with " << domainName << " port " << d2Name;
396+ }
397+ entry = index;
398+ }
399+
400+ for (size_t typeID = 0 ; typeID < numDomains; ++typeID) {
401+ auto association = associations[typeID];
402+ if (!association) {
403+ auto domainName = globals.circuitInfo .getDomain (typeID).getNameAttr ();
404+ auto portName = module .getPortNameAttr (i);
405+ return emitError (module .getPortLocation (i))
406+ << " missing " << domainName << " association for port "
407+ << portName;
408+ }
409+ }
410+ }
411+ }
412+
413+ return success ();
414+ }
415+
355416// ====--------------------------------------------------------------------------
356417// InferModuleDomains: Primary workhorse for inferring domains on modules.
357418// ====--------------------------------------------------------------------------
@@ -525,7 +586,7 @@ LogicalResult InferModuleDomains::operator()(FModuleOp module) {
525586}
526587
527588LogicalResult InferModuleDomains::processPorts (FModuleOp module ) {
528- auto portDomainInfo = module .getDomainInfoAttr ();
589+ auto domainInfo = module .getDomainInfoAttr ();
529590 auto numPorts = module .getNumPorts ();
530591
531592 // Process module ports - domain ports define explicit domains.
@@ -535,7 +596,7 @@ LogicalResult InferModuleDomains::processPorts(FModuleOp module) {
535596
536597 // This is a domain port.
537598 if (isa<DomainType>(port.getType ())) {
538- auto typeID = globals.circuitInfo .getDomainTypeID (portDomainInfo , i);
599+ auto typeID = globals.circuitInfo .getDomainTypeID (domainInfo , i);
539600 domainTypeIDTable[i] = typeID;
540601 if (module .getPortDirection (i) == Direction::In) {
541602 setTermForDomain (port, allocate<ValueTerm>(port));
@@ -544,7 +605,7 @@ LogicalResult InferModuleDomains::processPorts(FModuleOp module) {
544605 }
545606
546607 // This is a port, which may have explicit domain information.
547- auto portDomains = getPortDomainAssociation (portDomainInfo , i);
608+ auto portDomains = getPortDomainAssociation (domainInfo , i);
548609 if (portDomains.empty ())
549610 continue ;
550611
@@ -1305,13 +1366,34 @@ void InferModuleDomains::emitDomainPortInferenceError(T op, size_t i) const {
13051366 }
13061367}
13071368
1369+ static LogicalResult inferModuleDomains (GlobalState &globals,
1370+ FModuleOp module ) {
1371+ return InferModuleDomains::run (globals, module );
1372+ }
1373+
13081374// ===---------------------------------------------------------------------------
13091375// InferDomainsPass: Top-level pass implementation.
13101376// ===---------------------------------------------------------------------------
13111377
1378+ static LogicalResult runOnModuleLike (bool inferPublic, GlobalState &globals,
1379+ Operation *op) {
1380+ if (auto module = dyn_cast<FModuleOp>(op)) {
1381+ if (module .isPublic () && !inferPublic)
1382+ return checkModuleDomains (globals, module );
1383+ return inferModuleDomains (globals, module );
1384+ }
1385+
1386+ if (auto extModule = dyn_cast<FExtModuleOp>(op)) {
1387+ return checkModuleDomains (globals, extModule);
1388+ }
1389+
1390+ return success ();
1391+ }
1392+
13121393namespace {
13131394struct InferDomainsPass
13141395 : public circt::firrtl::impl::InferDomainsBase<InferDomainsPass> {
1396+ using InferDomainsBase::InferDomainsBase;
13151397 void runOnOperation () override ;
13161398};
13171399} // namespace
@@ -1320,16 +1402,11 @@ void InferDomainsPass::runOnOperation() {
13201402 LLVM_DEBUG (debugPassHeader (this ) << " \n " );
13211403 auto circuit = getOperation ();
13221404 auto &instanceGraph = getAnalysis<InstanceGraph>();
1323-
13241405 GlobalState globals (circuit);
13251406 DenseSet<InstanceGraphNode *> visited;
13261407 for (auto *root : instanceGraph) {
13271408 for (auto *node : llvm::post_order_ext (root, visited)) {
1328- auto module = dyn_cast<FModuleOp>(node->getOperation ());
1329- if (!module )
1330- continue ;
1331-
1332- if (failed (InferModuleDomains::run (globals, module ))) {
1409+ if (failed (runOnModuleLike (inferPublic, globals, node->getModule ()))) {
13331410 signalPassFailure ();
13341411 return ;
13351412 }
0 commit comments