141 size_t portID,
const PortInfo &port,
bool isFlip,
142 Twine name,
FIRRTLType type, uint64_t fieldID,
143 const FieldIDSearch<hw::InnerSymAttr> &syms,
144 const FieldIDSearch<AnnotationSet> &annos) {
145 auto *ctx = type.getContext();
147 .
Case<BundleType>([&](BundleType bundle) -> LogicalResult {
150 if (conv != Convention::Scalarized && bundle.isPassive()) {
151 auto lastId = fieldID + bundle.getMaxFieldID();
153 {{StringAttr::get(ctx, name), type,
154 isFlip ? Direction::Out : Direction::In,
162 for (
auto [idx, elem] : llvm::enumerate(bundle.getElements())) {
164 mod, newPorts, conv, portID, port, isFlip ^ elem.isFlip,
165 name +
"_" + elem.
name.getValue(), elem.type,
166 fieldID + bundle.getFieldID(idx), syms, annos)))
168 if (!syms.empty(fieldID, fieldID))
169 return mod.emitError(
"Port [")
171 <<
"] should be subdivided, but cannot be because of "
173 << port.
sym.getSymIfExists(fieldID) <<
"] on a bundle";
174 if (!annos.empty(fieldID, fieldID)) {
175 auto err = mod.emitError(
"Port [")
177 <<
"] should be subdivided, but cannot be because of "
179 auto [b, e] = annos.find(fieldID, fieldID);
180 err << b->getClass() <<
"(" << b->getFieldID() <<
")";
183 err <<
", " << b->getClass() <<
"(" << b->getFieldID() <<
")";
184 err <<
"] on a bundle";
191 .Case<FVectorType>([&](FVectorType vector) -> LogicalResult {
192 if (conv != Convention::Scalarized &&
193 vector.getElementType().isPassive()) {
194 auto lastId = fieldID + vector.getMaxFieldID();
196 {{StringAttr::get(ctx, name), type,
197 isFlip ? Direction::Out : Direction::In,
205 for (
size_t i = 0, e = vector.getNumElements(); i < e; ++i) {
207 mod, newPorts, conv, portID, port, isFlip,
208 name +
"_" + Twine(i), vector.getElementType(),
209 fieldID + vector.getFieldID(i), syms, annos)))
211 if (!syms.empty(fieldID, fieldID))
212 return mod.emitError(
"Port [")
214 <<
"] should be subdivided, but cannot be because of "
216 << port.
sym.getSymIfExists(fieldID) <<
"] on a vector";
217 if (!annos.empty(fieldID, fieldID)) {
218 auto err = mod.emitError(
"Port [")
220 <<
"] should be subdivided, but cannot be because of "
222 auto [b, e] = annos.find(fieldID, fieldID);
223 err << b->getClass();
226 err <<
", " << b->getClass();
227 err <<
"] on a vector";
237 {{StringAttr::get(ctx, name), type,
238 isFlip ? Direction::Out : Direction::In,
266 ImplicitLocOpBuilder theBuilder(module.getLoc(), module.getContext());
271 DenseMap<size_t, size_t> domainMap;
272 for (
auto &newPort : newPorts) {
273 if (!type_isa<DomainType>(newPort.type))
275 domainMap[newPort.portID] = newPort.resultID;
277 for (
auto &newPort : newPorts) {
278 if (type_isa<DomainType>(newPort.type))
280 auto oldAssociations = dyn_cast_or_null<ArrayAttr>(newPort.domains);
281 if (!oldAssociations)
283 SmallVector<Attribute> newAssociations;
284 for (
auto oldAttr : oldAssociations)
285 newAssociations.push_back(theBuilder.getUI32IntegerAttr(
286 domainMap[cast<IntegerAttr>(oldAttr).getValue().getZExtValue()]));
287 newPort.domains = theBuilder.getArrayAttr(newAssociations);
290 if (
auto mod = dyn_cast<FModuleOp>(module.getOperation())) {
291 Block *body = mod.getBodyBlock();
292 theBuilder.setInsertionPointToStart(body);
293 auto oldNumArgs = body->getNumArguments();
298 SmallVector<Value> bounceWires(oldNumArgs);
299 for (
auto &p : newPorts) {
300 auto newArg = body->addArgument(p.type, p.loc);
303 if (p.fieldID != 0) {
304 auto &wire = bounceWires[p.portID];
306 wire = WireOp::create(theBuilder, module.getPortType(p.portID),
307 module.getPortNameAttr(p.portID),
308 NameKindEnum::InterestingName)
311 bounceWires[p.portID] = newArg;
316 for (
auto idx = 0U; idx < oldNumArgs; ++idx) {
317 if (!bounceWires[idx]) {
318 bounceWires[idx] = WireOp::create(theBuilder, module.getPortType(idx),
319 module.getPortNameAttr(idx))
322 body->getArgument(idx).replaceAllUsesWith(bounceWires[idx]);
326 body->eraseArguments(0, oldNumArgs);
329 for (
auto &p : newPorts) {
330 if (isa<BlockArgument>(bounceWires[p.portID]))
334 theBuilder, body->getArgument(p.resultID),
340 body->getArgument(p.resultID));
344 SmallVector<NamedAttribute, 8> newModuleAttrs;
347 for (
auto attr :
module->getAttrDictionary())
350 if (attr.getName() != "portNames" && attr.getName() != "portDirections" &&
351 attr.getName() != "portTypes" && attr.getName() != "portAnnotations" &&
352 attr.getName() != "portSymbols" && attr.getName() != "portLocations")
353 newModuleAttrs.push_back(attr);
355 SmallVector<Direction> newPortDirections;
356 SmallVector<Attribute> newPortNames;
357 SmallVector<Attribute> newPortTypes;
358 SmallVector<Attribute> newPortSyms;
359 SmallVector<Attribute> newPortLocations;
360 SmallVector<Attribute, 8> newPortAnnotations;
361 SmallVector<Attribute> newPortDomains;
363 for (
auto p : newPorts) {
364 newPortTypes.push_back(TypeAttr::get(p.type));
365 newPortNames.push_back(p.name);
366 newPortDirections.push_back(p.direction);
367 newPortSyms.push_back(p.sym);
368 newPortLocations.push_back(p.loc);
369 newPortAnnotations.push_back(p.annotations.getArrayAttr());
370 newPortDomains.push_back(p.domains ? p.domains : cache.aEmpty);
373 newModuleAttrs.push_back(NamedAttribute(
374 cache.sPortDirections,
377 newModuleAttrs.push_back(
378 NamedAttribute(cache.sPortNames, theBuilder.getArrayAttr(newPortNames)));
380 newModuleAttrs.push_back(
381 NamedAttribute(cache.sPortTypes, theBuilder.getArrayAttr(newPortTypes)));
383 newModuleAttrs.push_back(NamedAttribute(
384 cache.sPortLocations, theBuilder.getArrayAttr(newPortLocations)));
386 newModuleAttrs.push_back(NamedAttribute(
387 cache.sPortAnnotations, theBuilder.getArrayAttr(newPortAnnotations)));
389 newModuleAttrs.push_back(NamedAttribute(
390 cache.sPortDomains, theBuilder.getArrayAttr(newPortDomains)));
393 module->setAttrs(newModuleAttrs);
394 FModuleLike::fixupPortSymsArray(newPortSyms, theBuilder.getContext());
395 module.setPortSymbols(newPortSyms);
400 const DenseMap<StringAttr, PortConversion> &ports) {
401 mod->walk([&](InstanceOp inst) ->
void {
402 ImplicitLocOpBuilder theBuilder(inst.getLoc(), inst);
403 const auto &modPorts = ports.at(inst.getModuleNameAttr().getAttr());
406 SmallVector<PortInfo> instPorts;
407 for (
auto p : modPorts) {
411 instPorts.push_back(p);
413 auto annos = inst.getAnnotations();
414 auto newOp = InstanceOp::create(
415 theBuilder, instPorts, inst.getModuleName(), inst.getName(),
416 inst.getNameKind(), annos.getValue(), inst.getLayers(),
417 inst.getLowerToBind(), inst.getDoNotPrint(), inst.getInnerSymAttr());
419 auto oldDict = inst->getDiscardableAttrDictionary();
420 auto newDict = newOp->getDiscardableAttrDictionary();
421 auto oldNames = inst.getPortNamesAttr();
422 SmallVector<NamedAttribute> newAttrs;
423 for (
auto na : oldDict)
424 if (!newDict.contains(na.getName()))
425 newOp->setDiscardableAttr(na.getName(), na.getValue());
428 SmallVector<WireOp> bounce(inst.getNumResults());
429 for (
auto p : modPorts) {
431 if (p.fieldID == 0) {
432 inst.getResult(p.portID).replaceAllUsesWith(
433 newOp.getResult(p.resultID));
436 if (!bounce[p.portID]) {
437 bounce[p.portID] = WireOp::create(
438 theBuilder, inst.getResult(p.portID).getType(),
439 theBuilder.getStringAttr(
440 inst.getName() +
"." +
441 cast<StringAttr>(oldNames[p.portID]).getValue()));
442 inst.getResult(p.portID).replaceAllUsesWith(
443 bounce[p.portID].getResult());
447 emitConnect(theBuilder, newOp.getResult(p.resultID),
454 newOp.getResult(p.resultID));
458 for (
auto *use : llvm::make_early_inc_range(inst->getUsers())) {
459 assert(isa<MatchingConnectOp>(use) || isa<ConnectOp>(use));
static std::unique_ptr< Context > context