27 std::function<bool(Type,
bool)> hasInputRef = [&](Type type,
28 bool output) ->
bool {
29 auto ftype = type_dyn_cast<FIRRTLType>(type);
30 if (!ftype || !ftype.containsReference())
33 .
Case<RefType>([&](
auto reftype) {
return !output; })
34 .Case<OpenVectorType>([&](OpenVectorType ovt) {
35 return hasInputRef(ovt.getElementType(), output);
37 .Case<OpenBundleType>([&](OpenBundleType obt) {
38 for (
auto field : obt.getElements())
39 if (hasInputRef(field.type, field.isFlip ^ output))
45 for (
auto &pi :
module.getPorts())
46 if (hasInputRef(pi.type, pi.isOutput()))
47 return emitError(pi.loc, "input probe not allowed");
54 auto portTypes =
module.getPortTypesAttr();
55 if (!portTypes || llvm::any_of(portTypes.getValue(), [](Attribute attr) {
56 return !isa<TypeAttr>(attr);
58 return module.emitOpError("requires valid port types");
60 auto numPorts = portTypes.size();
63 auto portDirections =
module.getPortDirectionsAttr();
65 return module.emitOpError("requires valid port direction");
68 auto bitWidth = portDirections.size();
69 if (
static_cast<size_t>(bitWidth) != numPorts)
70 return module.emitOpError("requires ") << numPorts << " port directions";
73 auto portNames =
module.getPortNamesAttr();
75 return module.emitOpError("requires valid port names");
76 if (portNames.size() != numPorts)
77 return module.emitOpError("requires ") << numPorts << " port names";
78 if (llvm::any_of(portNames.getValue(),
79 [](Attribute attr) { return !isa<StringAttr>(attr); }))
80 return module.emitOpError("port names should all be string attributes");
83 auto portAnnotations =
module.getPortAnnotationsAttr();
85 return module.emitOpError("requires valid port annotations");
87 if (!portAnnotations.empty() && portAnnotations.size() != numPorts)
88 return module.emitOpError("requires ") << numPorts << " port annotations";
90 for (
auto annos : portAnnotations.getValue()) {
91 auto arrayAttr = dyn_cast<ArrayAttr>(annos);
93 return module.emitOpError(
94 "requires port annotations be array attributes");
95 if (llvm::any_of(arrayAttr.getValue(),
96 [](Attribute attr) { return !isa<DictionaryAttr>(attr); }))
97 return module.emitOpError(
98 "annotations must be dictionaries or subannotations");
102 auto portSymbols =
module.getPortSymbolsAttr();
104 return module.emitOpError("requires valid port symbols");
105 if (!portSymbols.empty() && portSymbols.size() != numPorts)
106 return module.emitOpError("requires ") << numPorts << " port symbols";
107 if (llvm::any_of(portSymbols.getValue(), [](Attribute attr) {
108 return !attr || !isa<hw::InnerSymAttr>(attr);
110 return module.emitOpError("port symbols should all be InnerSym attributes");
113 auto portLocs =
module.getPortLocationsAttr();
115 return module.emitOpError("requires valid port locations");
116 if (portLocs.size() != numPorts)
117 return module.emitOpError("requires ") << numPorts << " port locations";
118 if (llvm::any_of(portLocs.getValue(), [](Attribute attr) {
119 return !attr || !isa<LocationAttr>(attr);
121 return module.emitOpError("port symbols should all be location attributes");
133 auto domains =
module.getDomainInfoAttr();
136 return module.emitOpError("requires valid port domains");
138 if (!domains.empty() && domains.size() != numPorts)
139 return module.emitOpError("requires ")
140 << numPorts << " port domains, but has " << domains.size();
142 for (
auto [index, port] : llvm::enumerate(module.getPorts())) {
143 auto type = cast<TypeAttr>(portTypes[index]).getValue();
146 if (isa<DomainType>(type)) {
148 return module.emitOpError() << "has domain port '" << port.getName()
149 << "', but no domain information";
150 if (!isa<FlatSymbolRefAttr>(domains[index]))
151 return module.emitOpError() << "domain information for domain port '"
152 << module.getPortName(index)
153 << "' must be a 'FlatSymbolRefAttr'";
163 auto domain = domains[index];
164 auto arrayAttr = dyn_cast<ArrayAttr>(domain);
166 return module.emitOpError()
167 << "domain information for non-domain port '"
168 << module.getPortName(index) << "' must be an 'ArrayAttr'";
169 for (
auto attr : arrayAttr) {
170 auto association = dyn_cast<IntegerAttr>(attr);
172 return module.emitOpError()
173 << "domain information for non-domain port '"
174 << module.getPortName(index)
175 << "' must be an 'ArrayAttr<IntegerAttr>'";
176 auto associationIdx = association.getValue().getZExtValue();
177 if (associationIdx >= numPorts)
178 return module.emitOpError()
179 << "has domain association " << associationIdx << " for port '"
180 << module.getPortName(index) << "', but the module only has "
181 << numPorts << " ports";
182 if (!type_isa<DomainType>(module.getPortType(associationIdx)))
183 return module.emitOpError()
184 << "has port '" << module.getPortName(index)
185 << "' which has a domain association with non-domain port '"
186 << module.getPortName(associationIdx) << "'";
191 if (module->getNumRegions() != 1)
192 return module.emitOpError("requires one region");
static std::unique_ptr< Context > context