45 #include "mlir/IR/ImplicitLocOpBuilder.h"
46 #include "mlir/IR/Threading.h"
47 #include "llvm/ADT/APSInt.h"
48 #include "llvm/ADT/BitVector.h"
49 #include "llvm/Support/Debug.h"
50 #include "llvm/Support/Parallel.h"
52 #define DEBUG_TYPE "firrtl-lower-types"
54 using namespace circt;
55 using namespace firrtl;
60 struct FlatBundleFieldEntry {
68 SmallString<16> suffix;
73 unsigned fieldID, StringRef suffix,
bool isOutput)
74 : type(type), index(index), fieldID(fieldID), suffix(suffix),
78 llvm::errs() <<
"FBFE{" << type <<
" index<" << index <<
"> fieldID<"
79 << fieldID <<
"> suffix<" << suffix <<
"> isOutput<"
80 << isOutput <<
">}\n";
85 struct PortInfoWithIP {
87 std::optional<InternalPathAttr> internalPath;
94 return mapBaseType(type, [&](
auto) {
return fieldType; });
99 auto ftype = type_dyn_cast<FIRRTLType>(type);
108 .
Case<BundleType>([&](
auto bundle) {
return false; })
109 .Case<FVectorType>([&](FVectorType vector) {
111 return vector.getElementType().isGround() &&
112 vector.getNumElements() > 1;
114 .Default([](
auto groundType) {
return true; });
121 .
Case<BundleType>([&](
auto bundle) {
return true; })
122 .Case<FVectorType>([&](FVectorType vector) {
125 .Default([](
auto groundType) {
return false; });
132 if (
auto refType = type_dyn_cast<RefType>(type)) {
134 if (refType.getForceable())
145 auto firrtlType = type_dyn_cast<FIRRTLBaseType>(type);
151 if (!firrtlType.isPassive() || firrtlType.containsAnalog() ||
163 llvm_unreachable(
"unexpected mode");
169 static bool peelType(Type type, SmallVectorImpl<FlatBundleFieldEntry> &fields,
176 if (
auto refType = type_dyn_cast<RefType>(type))
177 type = refType.getType();
179 .
Case<BundleType>([&](
auto bundle) {
180 SmallString<16> tmpSuffix;
182 for (
size_t i = 0, e = bundle.getNumElements(); i < e; ++i) {
183 auto elt = bundle.getElement(i);
186 tmpSuffix.push_back(
'_');
187 tmpSuffix.append(elt.name.getValue());
188 fields.emplace_back(elt.type, i, bundle.getFieldID(i), tmpSuffix,
193 .Case<FVectorType>([&](
auto vector) {
195 for (
size_t i = 0, e = vector.getNumElements(); i != e; ++i) {
196 fields.emplace_back(vector.getElementType(), i, vector.getFieldID(i),
197 "_" + std::to_string(i),
false);
201 .Default([](
auto op) {
return false; });
207 SubaccessOp sao = llvm::dyn_cast<SubaccessOp>(op);
211 llvm::dyn_cast_or_null<ConstantOp>(sao.getIndex().getDefiningOp());
212 return arg && sao.getInput().getType().base().getNumElements() != 0;
217 SmallVector<Operation *> retval;
218 auto defOp = op->getOperand(0).getDefiningOp();
219 while (isa_and_nonnull<SubfieldOp, SubindexOp, SubaccessOp>(defOp)) {
220 retval.push_back(defOp);
221 defOp = defOp->getOperand(0).getDefiningOp();
231 FlatBundleFieldEntry field) {
232 SmallVector<Type, 8> ports;
233 SmallVector<Attribute, 8> portNames;
234 SmallVector<Attribute, 8> portLocations;
236 auto oldPorts = op.getPorts();
237 for (
size_t portIdx = 0, e = oldPorts.size(); portIdx < e; ++portIdx) {
238 auto port = oldPorts[portIdx];
240 MemOp::getTypeForPort(op.getDepth(), field.type, port.second));
241 portNames.push_back(port.first);
245 auto newMem = b->create<MemOp>(
246 ports, op.getReadLatency(), op.getWriteLatency(), op.getDepth(),
247 op.getRuw(), portNames, (op.getName() + field.suffix).str(),
248 op.getNameKind(), op.getAnnotations().getValue(),
249 op.getPortAnnotations().getValue(), op.getInnerSymAttr());
251 if (op.getInnerSym()) {
252 op.emitError(
"cannot split memory with symbol present");
256 SmallVector<Attribute> newAnnotations;
257 for (
size_t portIdx = 0, e = newMem.getNumResults(); portIdx < e; ++portIdx) {
258 auto portType = type_cast<BundleType>(newMem.getResult(portIdx).getType());
259 auto oldPortType = type_cast<BundleType>(op.getResult(portIdx).getType());
260 SmallVector<Attribute> portAnno;
261 for (
auto attr : newMem.getPortAnnotation(portIdx)) {
264 auto targetIndex = oldPortType.getIndexForFieldID(annoFieldID);
268 if (annoFieldID == oldPortType.getFieldID(targetIndex)) {
271 b->getI32IntegerAttr(portType.getFieldID(targetIndex)));
272 portAnno.push_back(anno.
getDict());
277 if (type_isa<BundleType>(oldPortType.getElement(targetIndex).type)) {
282 auto fieldID = field.fieldID + oldPortType.getFieldID(targetIndex);
283 if (annoFieldID >= fieldID &&
288 annoFieldID - fieldID + portType.getFieldID(targetIndex);
289 anno.
setMember(
"circt.fieldID", b->getI32IntegerAttr(newFieldID));
290 portAnno.push_back(anno.
getDict());
294 portAnno.push_back(attr);
296 newAnnotations.push_back(b->getArrayAttr(portAnno));
298 newMem.setAllPortAnnotations(newAnnotations);
308 AttrCache(MLIRContext *context) {
320 AttrCache(
const AttrCache &) =
default;
323 StringAttr nameAttr, nameKindAttr, sPortDirections, sPortNames, sPortTypes,
324 sPortSyms, sPortLocations, sPortAnnotations, sEmpty;
329 struct TypeLoweringVisitor :
public FIRRTLVisitor<TypeLoweringVisitor, bool> {
334 SymbolTable &symTbl,
const AttrCache &cache,
335 const llvm::DenseMap<FModuleLike, Convention> &conventionTable)
336 : context(context), aggregatePreservationMode(preserveAggregate),
337 memoryPreservationMode(memoryPreservationMode), symTbl(symTbl),
338 cache(cache), conventionTable(conventionTable) {}
345 void lowerModule(FModuleLike op);
347 bool lowerArg(FModuleLike module,
size_t argIndex,
size_t argsRemoved,
348 SmallVectorImpl<PortInfoWithIP> &newArgs,
349 SmallVectorImpl<Value> &lowering);
350 std::pair<Value, PortInfoWithIP>
351 addArg(Operation *module,
unsigned insertPt,
unsigned insertPtOffset,
352 FIRRTLType srcType,
const FlatBundleFieldEntry &field,
353 PortInfoWithIP &oldArg, hw::InnerSymAttr newSym);
356 bool visitDecl(FExtModuleOp op);
357 bool visitDecl(FModuleOp op);
358 bool visitDecl(InstanceOp op);
359 bool visitDecl(MemOp op);
360 bool visitDecl(NodeOp op);
361 bool visitDecl(RegOp op);
362 bool visitDecl(WireOp op);
363 bool visitDecl(RegResetOp op);
364 bool visitExpr(InvalidValueOp op);
365 bool visitExpr(SubaccessOp op);
366 bool visitExpr(VectorCreateOp op);
367 bool visitExpr(BundleCreateOp op);
368 bool visitExpr(ElementwiseAndPrimOp op);
369 bool visitExpr(ElementwiseOrPrimOp op);
370 bool visitExpr(ElementwiseXorPrimOp op);
371 bool visitExpr(MultibitMuxOp op);
372 bool visitExpr(MuxPrimOp op);
373 bool visitExpr(Mux2CellIntrinsicOp op);
374 bool visitExpr(Mux4CellIntrinsicOp op);
375 bool visitExpr(BitCastOp op);
376 bool visitExpr(RefSendOp op);
377 bool visitExpr(RefResolveOp op);
378 bool visitExpr(RefCastOp op);
379 bool visitStmt(ConnectOp op);
380 bool visitStmt(StrictConnectOp op);
381 bool visitStmt(RefDefineOp op);
382 bool visitStmt(WhenOp op);
383 bool visitStmt(LayerBlockOp op);
384 bool visitUnrealizedConversionCast(mlir::UnrealizedConversionCastOp op);
386 bool isFailed()
const {
return encounteredError; }
388 bool visitInvalidOp(Operation *op) {
389 if (
auto castOp = dyn_cast<mlir::UnrealizedConversionCastOp>(op))
390 return visitUnrealizedConversionCast(castOp);
395 void processUsers(Value val, ArrayRef<Value> mapping);
396 bool processSAPath(Operation *);
397 void lowerBlock(Block *);
398 void lowerSAWritePath(Operation *, ArrayRef<Operation *> writePath);
408 llvm::function_ref<Value(
const FlatBundleFieldEntry &, ArrayAttr)> clone,
413 ArrayAttr filterAnnotations(MLIRContext *
ctxt, ArrayAttr annotations,
414 FIRRTLType srcType, FlatBundleFieldEntry field);
418 LogicalResult partitionSymbols(hw::InnerSymAttr sym,
FIRRTLType parentType,
419 SmallVectorImpl<hw::InnerSymAttr> &newSyms,
423 getPreservationModeForModule(FModuleLike moduleLike);
424 Value getSubWhatever(Value val,
size_t index);
426 size_t uniqueIdx = 0;
427 std::string uniqueName() {
428 auto myID = uniqueIdx++;
429 return (Twine(
"__GEN_") + Twine(myID)).str();
432 MLIRContext *context;
445 const AttrCache &cache;
447 const llvm::DenseMap<FModuleLike, Convention> &conventionTable;
450 bool encounteredError =
false;
457 TypeLoweringVisitor::getPreservationModeForModule(FModuleLike module) {
458 auto lookup = conventionTable.find(module);
459 if (lookup == conventionTable.end())
460 return aggregatePreservationMode;
461 switch (lookup->second) {
462 case Convention::Scalarized:
464 case Convention::Internal:
465 return aggregatePreservationMode;
467 llvm_unreachable(
"Unknown convention");
468 return aggregatePreservationMode;
471 Value TypeLoweringVisitor::getSubWhatever(Value val,
size_t index) {
472 if (type_isa<BundleType>(val.getType()))
473 return builder->create<SubfieldOp>(val, index);
474 if (type_isa<FVectorType>(val.getType()))
475 return builder->create<SubindexOp>(val, index);
476 if (type_isa<RefType>(val.getType()))
477 return builder->create<RefSubOp>(val, index);
478 llvm_unreachable(
"Unknown aggregate type");
483 bool TypeLoweringVisitor::processSAPath(Operation *op) {
486 if (writePath.empty())
489 lowerSAWritePath(op, writePath);
492 op->eraseOperands(0, 2);
494 for (
size_t i = 0; i < writePath.size(); ++i) {
495 if (writePath[i]->use_empty()) {
496 writePath[i]->erase();
504 void TypeLoweringVisitor::lowerBlock(Block *block) {
506 for (
auto it = block->rbegin(), e = block->rend(); it != e;) {
508 builder->setInsertionPoint(&iop);
510 bool removeOp = dispatchVisitor(&iop);
519 ArrayAttr TypeLoweringVisitor::filterAnnotations(MLIRContext *
ctxt,
520 ArrayAttr annotations,
522 FlatBundleFieldEntry field) {
523 SmallVector<Attribute> retval;
524 if (!annotations || annotations.empty())
526 for (
auto opAttr : annotations) {
528 auto fieldID = anno.getFieldID();
529 anno.removeMember(
"circt.fieldID");
534 retval.push_back(anno.getAttr());
539 if (fieldID < field.fieldID ||
544 if (
auto newFieldID = fieldID - field.fieldID) {
547 anno.setMember(
"circt.fieldID",
builder->getI32IntegerAttr(newFieldID));
550 retval.push_back(anno.getAttr());
555 LogicalResult TypeLoweringVisitor::partitionSymbols(
557 SmallVectorImpl<hw::InnerSymAttr> &newSyms, Location errorLoc) {
560 if (!sym || sym.empty())
563 auto *context = sym.getContext();
567 return mlir::emitError(errorLoc,
568 "unable to partition symbol on unsupported type ")
571 return TypeSwitch<FIRRTLType, LogicalResult>(baseType)
572 .Case<BundleType, FVectorType>([&](
auto aggType) -> LogicalResult {
576 hw::InnerSymPropertiesAttr prop;
580 SmallVector<BinningInfo> binning;
581 for (
auto prop : sym) {
582 auto fieldID = prop.getFieldID();
585 return mlir::emitError(errorLoc,
"unable to lower due to symbol ")
587 <<
" with target not preserved by lowering";
588 auto [index, relFieldID] = aggType.getIndexAndSubfieldID(fieldID);
589 binning.push_back({index, relFieldID, prop});
593 llvm::stable_sort(binning, [&](
auto &lhs,
auto &rhs) {
594 return std::tuple(lhs.index, lhs.relFieldID) <
595 std::tuple(rhs.index, rhs.relFieldID);
600 newSyms.resize(aggType.getNumElements());
601 for (
auto binIt = binning.begin(), binEnd = binning.end();
603 auto curIndex = binIt->index;
604 SmallVector<hw::InnerSymPropertiesAttr> propsForIndex;
606 while (binIt != binEnd && binIt->index == curIndex) {
608 context, binIt->prop.getName(), binIt->relFieldID,
609 binIt->prop.getSymVisibility()));
613 assert(!newSyms[curIndex]);
618 .Default([&](
auto ty) {
619 return mlir::emitError(
620 errorLoc,
"unable to partition symbol on unsupported type ")
625 bool TypeLoweringVisitor::lowerProducer(
627 llvm::function_ref<Value(
const FlatBundleFieldEntry &, ArrayAttr)> clone,
631 srcType = op->getResult(0).getType();
632 auto srcFType = type_dyn_cast<FIRRTLType>(srcType);
635 SmallVector<FlatBundleFieldEntry, 8> fieldTypes;
637 if (!
peelType(srcFType, fieldTypes, aggregatePreservationMode))
640 SmallVector<Value> lowered;
642 SmallString<16> loweredName;
643 auto nameKindAttr = op->getAttrOfType<NameKindEnumAttr>(cache.nameKindAttr);
645 if (
auto nameAttr = op->getAttrOfType<StringAttr>(cache.nameAttr))
646 loweredName = nameAttr.getValue();
647 auto baseNameLen = loweredName.size();
648 auto oldAnno = dyn_cast_or_null<ArrayAttr>(op->getAttr(
"annotations"));
650 SmallVector<hw::InnerSymAttr> fieldSyms(fieldTypes.size());
651 if (
auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(op)) {
652 if (failed(partitionSymbols(symOp.getInnerSymAttr(), srcFType, fieldSyms,
654 encounteredError =
true;
659 for (
const auto &[field, sym] : llvm::zip_equal(fieldTypes, fieldSyms)) {
660 if (!loweredName.empty()) {
661 loweredName.resize(baseNameLen);
662 loweredName += field.suffix;
667 ArrayAttr loweredAttrs =
668 filterAnnotations(context, oldAnno, srcFType, field);
669 auto newVal = clone(field, loweredAttrs);
675 auto newSymOp = newVal.getDefiningOp<hw::InnerSymbolOpInterface>();
678 "op with inner symbol lowered to op that cannot take inner symbol");
679 newSymOp.setInnerSymbolAttr(sym);
683 if (
auto *newOp = newVal.getDefiningOp()) {
684 if (!loweredName.empty())
687 newOp->setAttr(cache.nameKindAttr, nameKindAttr);
689 lowered.push_back(newVal);
692 processUsers(op->getResult(0), lowered);
696 void TypeLoweringVisitor::processUsers(Value val, ArrayRef<Value> mapping) {
697 for (
auto *user : llvm::make_early_inc_range(val.getUsers())) {
698 TypeSwitch<Operation *, void>(user)
699 .Case<SubindexOp>([mapping](SubindexOp sio) {
700 Value repl = mapping[sio.getIndex()];
701 sio.replaceAllUsesWith(repl);
704 .Case<SubfieldOp>([mapping](SubfieldOp sfo) {
706 Value repl = mapping[sfo.getFieldIndex()];
707 sfo.replaceAllUsesWith(repl);
710 .Case<RefSubOp>([mapping](RefSubOp refSub) {
711 Value repl = mapping[refSub.getIndex()];
712 refSub.replaceAllUsesWith(repl);
715 .Default([&](
auto op) {
726 ImplicitLocOpBuilder b(user->getLoc(), user);
730 assert(llvm::none_of(mapping, [](
auto v) {
731 auto fbasetype = type_dyn_cast<FIRRTLBaseType>(v.getType());
732 return !fbasetype || fbasetype.containsReference();
736 TypeSwitch<Type, Value>(val.getType())
737 .template Case<FVectorType>([&](
auto vecType) {
738 return b.createOrFold<VectorCreateOp>(vecType, mapping);
740 .
template Case<BundleType>([&](
auto bundleType) {
741 return b.createOrFold<BundleCreateOp>(bundleType, mapping);
743 .Default([&](
auto _) -> Value {
return {}; });
745 user->emitError(
"unable to reconstruct source of type ")
747 encounteredError =
true;
750 user->replaceUsesOfWith(val, input);
755 void TypeLoweringVisitor::lowerModule(FModuleLike op) {
756 if (
auto module = llvm::dyn_cast<FModuleOp>(*op))
758 else if (
auto extModule = llvm::dyn_cast<FExtModuleOp>(*op))
759 visitDecl(extModule);
765 std::pair<Value, PortInfoWithIP>
766 TypeLoweringVisitor::addArg(Operation *module,
unsigned insertPt,
768 const FlatBundleFieldEntry &field,
769 PortInfoWithIP &oldArg, hw::InnerSymAttr newSym) {
772 if (
auto mod = llvm::dyn_cast<FModuleOp>(module)) {
773 Block *body = mod.getBodyBlock();
775 newValue = body->insertArgument(insertPt, fieldType, oldArg.pi.loc);
779 auto name =
builder->getStringAttr(oldArg.pi.name.getValue() + field.suffix);
782 auto newAnnotations = filterAnnotations(
783 context, oldArg.pi.annotations.getArrayAttr(), srcType, field);
785 auto direction = (
Direction)((
unsigned)oldArg.pi.direction ^ field.isOutput);
787 return std::make_pair(
789 PortInfoWithIP{
PortInfo{name, fieldType, direction, newSym, oldArg.pi.loc,
791 oldArg.internalPath});
795 bool TypeLoweringVisitor::lowerArg(FModuleLike module,
size_t argIndex,
797 SmallVectorImpl<PortInfoWithIP> &newArgs,
798 SmallVectorImpl<Value> &lowering) {
801 SmallVector<FlatBundleFieldEntry> fieldTypes;
802 auto srcType = type_cast<FIRRTLType>(newArgs[argIndex].pi.type);
803 if (!
peelType(srcType, fieldTypes, getPreservationModeForModule(module)))
807 if (
auto ip = newArgs[argIndex].internalPath; ip && ip->getPath()) {
808 ::mlir::emitError(newArgs[argIndex].pi.loc,
809 "cannot lower port with internal path");
810 encounteredError =
true;
814 SmallVector<hw::InnerSymAttr> fieldSyms(fieldTypes.size());
815 if (failed(partitionSymbols(newArgs[argIndex].pi.sym, srcType, fieldSyms,
816 newArgs[argIndex].pi.loc))) {
817 encounteredError =
true;
821 for (
const auto &[idx, field, fieldSym] :
822 llvm::enumerate(fieldTypes, fieldSyms)) {
823 auto newValue = addArg(module, 1 + argIndex + idx, argsRemoved, srcType,
824 field, newArgs[argIndex], fieldSym);
825 newArgs.insert(newArgs.begin() + 1 + argIndex + idx, newValue.second);
827 lowering.push_back(newValue.first);
834 if (
auto rop = llvm::dyn_cast<SubfieldOp>(op))
835 return builder->create<SubfieldOp>(rhs, rop.getFieldIndex());
836 if (
auto rop = llvm::dyn_cast<SubindexOp>(op))
837 return builder->create<SubindexOp>(rhs, rop.getIndex());
838 if (
auto rop = llvm::dyn_cast<SubaccessOp>(op))
839 return builder->create<SubaccessOp>(rhs, rop.getIndex());
840 op->emitError(
"Unknown accessor");
844 void TypeLoweringVisitor::lowerSAWritePath(Operation *op,
845 ArrayRef<Operation *> writePath) {
846 SubaccessOp sao = cast<SubaccessOp>(writePath.back());
847 FVectorType saoType = sao.getInput().getType();
848 auto selectWidth = llvm::Log2_64_Ceil(saoType.getNumElements());
850 for (
size_t index = 0, e = saoType.getNumElements(); index < e; ++index) {
851 auto cond =
builder->create<EQPrimOp>(
854 APInt(selectWidth, index)));
855 builder->create<WhenOp>(cond,
false, [&]() {
857 Value leaf =
builder->create<SubindexOp>(sao.getInput(), index);
858 for (
int i = writePath.size() - 2; i >= 0; --i) {
862 encounteredError =
true;
873 bool TypeLoweringVisitor::visitStmt(ConnectOp op) {
874 if (processSAPath(op))
878 SmallVector<FlatBundleFieldEntry> fields;
885 for (
const auto &field : llvm::enumerate(fields)) {
886 Value src = getSubWhatever(op.getSrc(), field.index());
887 Value dest = getSubWhatever(op.getDest(), field.index());
888 if (field.value().isOutput)
889 std::swap(src, dest);
896 bool TypeLoweringVisitor::visitStmt(StrictConnectOp op) {
897 if (processSAPath(op))
901 SmallVector<FlatBundleFieldEntry> fields;
908 for (
const auto &field : llvm::enumerate(fields)) {
909 Value src = getSubWhatever(op.getSrc(), field.index());
910 Value dest = getSubWhatever(op.getDest(), field.index());
911 if (field.value().isOutput)
912 std::swap(src, dest);
913 builder->create<StrictConnectOp>(dest, src);
919 bool TypeLoweringVisitor::visitStmt(RefDefineOp op) {
921 SmallVector<FlatBundleFieldEntry> fields;
923 if (!
peelType(op.getDest().getType(), fields, aggregatePreservationMode))
927 for (
const auto &field : llvm::enumerate(fields)) {
928 Value src = getSubWhatever(op.getSrc(), field.index());
929 Value dest = getSubWhatever(op.getDest(), field.index());
930 assert(!field.value().isOutput &&
"unexpected flip in reftype destination");
931 builder->create<RefDefineOp>(dest, src);
936 bool TypeLoweringVisitor::visitStmt(WhenOp op) {
942 lowerBlock(&op.getThenBlock());
945 if (op.hasElseRegion())
946 lowerBlock(&op.getElseBlock());
951 bool TypeLoweringVisitor::visitStmt(LayerBlockOp op) {
952 lowerBlock(op.getBody());
958 bool TypeLoweringVisitor::visitDecl(MemOp op) {
960 SmallVector<FlatBundleFieldEntry> fields;
963 if (!
peelType(op.getDataType(), fields, memoryPreservationMode))
966 if (op.getInnerSym()) {
967 op->emitError() <<
"has a symbol, but no symbols may exist on aggregates "
968 "passed through LowerTypes";
969 encounteredError =
true;
973 SmallVector<MemOp> newMemories;
974 SmallVector<WireOp> oldPorts;
977 for (
unsigned int index = 0, end = op.getNumResults(); index < end; ++index) {
978 auto result = op.getResult(index);
979 if (op.getPortKind(index) == MemOp::PortKind::Debug) {
980 op.emitOpError(
"cannot lower memory with debug port");
981 encounteredError =
true;
984 auto wire =
builder->create<WireOp>(
986 (op.getName() +
"_" + op.getPortName(index).getValue()).str());
987 oldPorts.push_back(wire);
988 result.replaceAllUsesWith(wire.getResult());
995 for (
const auto &field : fields) {
997 if (!newMemForField) {
998 op.emitError(
"failed cloning memory for field");
999 encounteredError =
true;
1002 newMemories.push_back(newMemForField);
1005 for (
size_t index = 0, rend = op.getNumResults(); index < rend; ++index) {
1006 auto result = oldPorts[index].getResult();
1007 auto rType = type_cast<BundleType>(result.getType());
1008 for (
size_t fieldIndex = 0, fend = rType.getNumElements();
1009 fieldIndex != fend; ++fieldIndex) {
1010 auto name = rType.getElement(fieldIndex).name.getValue();
1011 auto oldField =
builder->create<SubfieldOp>(result, fieldIndex);
1014 if (name ==
"data" || name ==
"mask" || name ==
"wdata" ||
1015 name ==
"wmask" || name ==
"rdata") {
1016 for (
const auto &field : fields) {
1017 auto realOldField = getSubWhatever(oldField, field.index);
1018 auto newField = getSubWhatever(
1019 newMemories[field.index].getResult(index), fieldIndex);
1020 if (rType.getElement(fieldIndex).isFlip)
1021 std::swap(realOldField, newField);
1025 for (
auto mem : newMemories) {
1027 builder->create<SubfieldOp>(mem.getResult(index), fieldIndex);
1036 bool TypeLoweringVisitor::visitDecl(FExtModuleOp extModule) {
1037 ImplicitLocOpBuilder theBuilder(extModule.getLoc(), context);
1043 auto internalPaths = extModule.getInternalPaths();
1046 SmallVector<unsigned> argsToRemove;
1047 SmallVector<PortInfoWithIP> newArgs;
1048 for (
auto [idx, pi] : llvm::enumerate(extModule.getPorts())) {
1049 std::optional<InternalPathAttr> internalPath;
1051 internalPath = cast<InternalPathAttr>(internalPaths->getValue()[idx]);
1052 newArgs.push_back({pi, internalPath});
1055 for (
size_t argIndex = 0, argsRemoved = 0; argIndex < newArgs.size();
1057 SmallVector<Value> lowering;
1058 if (lowerArg(extModule, argIndex, argsRemoved, newArgs, lowering)) {
1059 argsToRemove.push_back(argIndex);
1066 for (
auto toRemove : llvm::reverse(argsToRemove))
1067 newArgs.erase(newArgs.begin() + toRemove);
1069 SmallVector<NamedAttribute, 8> newModuleAttrs;
1072 for (
auto attr : extModule->getAttrDictionary())
1075 if (attr.getName() !=
"portDirections" && attr.getName() !=
"portNames" &&
1076 attr.getName() !=
"portTypes" && attr.getName() !=
"portAnnotations" &&
1077 attr.getName() !=
"portSyms" && attr.getName() !=
"portLocations")
1078 newModuleAttrs.push_back(attr);
1080 SmallVector<Direction> newArgDirections;
1081 SmallVector<Attribute> newArgNames;
1082 SmallVector<Attribute, 8> newArgTypes;
1083 SmallVector<Attribute, 8> newArgSyms;
1084 SmallVector<Attribute, 8> newArgLocations;
1085 SmallVector<Attribute, 8> newArgAnnotations;
1086 SmallVector<Attribute, 8> newInternalPaths;
1089 for (
auto &port : newArgs) {
1090 newArgDirections.push_back(port.pi.direction);
1091 newArgNames.push_back(port.pi.name);
1093 newArgSyms.push_back(port.pi.sym);
1094 newArgLocations.push_back(port.pi.loc);
1095 newArgAnnotations.push_back(port.pi.annotations.getArrayAttr());
1097 newInternalPaths.push_back(port.internalPath.value_or(emptyInternalPath));
1100 newModuleAttrs.push_back(
1101 NamedAttribute(cache.sPortDirections,
1104 newModuleAttrs.push_back(
1105 NamedAttribute(cache.sPortNames,
builder.getArrayAttr(newArgNames)));
1107 newModuleAttrs.push_back(
1108 NamedAttribute(cache.sPortTypes,
builder.getArrayAttr(newArgTypes)));
1110 newModuleAttrs.push_back(NamedAttribute(
1111 cache.sPortLocations,
builder.getArrayAttr(newArgLocations)));
1113 newModuleAttrs.push_back(NamedAttribute(
1114 cache.sPortAnnotations,
builder.getArrayAttr(newArgAnnotations)));
1117 extModule->setAttrs(newModuleAttrs);
1118 extModule.setPortSymbols(newArgSyms);
1120 extModule.setInternalPathsAttr(
builder.getArrayAttr(newInternalPaths));
1125 bool TypeLoweringVisitor::visitDecl(FModuleOp module) {
1126 auto *body = module.getBodyBlock();
1128 ImplicitLocOpBuilder theBuilder(module.getLoc(), context);
1135 llvm::BitVector argsToRemove;
1136 auto newArgs = llvm::map_to_vector(module.getPorts(), [](
auto pi) {
1137 return PortInfoWithIP{pi, std::nullopt};
1139 for (
size_t argIndex = 0, argsRemoved = 0; argIndex < newArgs.size();
1141 SmallVector<Value> lowerings;
1142 if (lowerArg(module, argIndex, argsRemoved, newArgs, lowerings)) {
1143 auto arg = module.getArgument(argIndex);
1144 processUsers(arg, lowerings);
1145 argsToRemove.push_back(
true);
1148 argsToRemove.push_back(
false);
1153 body->eraseArguments(argsToRemove);
1154 for (
auto deadArg = argsToRemove.find_last(); deadArg != -1;
1155 deadArg = argsToRemove.find_prev(deadArg))
1156 newArgs.erase(newArgs.begin() + deadArg);
1158 SmallVector<NamedAttribute, 8> newModuleAttrs;
1161 for (
auto attr : module->getAttrDictionary())
1164 if (attr.getName() !=
"portNames" && attr.getName() !=
"portDirections" &&
1165 attr.getName() !=
"portTypes" && attr.getName() !=
"portAnnotations" &&
1166 attr.getName() !=
"portSyms" && attr.getName() !=
"portLocations")
1167 newModuleAttrs.push_back(attr);
1169 SmallVector<Direction> newArgDirections;
1170 SmallVector<Attribute> newArgNames;
1171 SmallVector<Attribute> newArgTypes;
1172 SmallVector<Attribute> newArgSyms;
1173 SmallVector<Attribute> newArgLocations;
1174 SmallVector<Attribute, 8> newArgAnnotations;
1175 for (
auto &port : newArgs) {
1176 newArgDirections.push_back(port.pi.direction);
1177 newArgNames.push_back(port.pi.name);
1179 newArgSyms.push_back(port.pi.sym);
1180 newArgLocations.push_back(port.pi.loc);
1181 newArgAnnotations.push_back(port.pi.annotations.getArrayAttr());
1184 newModuleAttrs.push_back(
1185 NamedAttribute(cache.sPortDirections,
1188 newModuleAttrs.push_back(
1189 NamedAttribute(cache.sPortNames,
builder->getArrayAttr(newArgNames)));
1191 newModuleAttrs.push_back(
1192 NamedAttribute(cache.sPortTypes,
builder->getArrayAttr(newArgTypes)));
1194 newModuleAttrs.push_back(NamedAttribute(
1195 cache.sPortLocations,
builder->getArrayAttr(newArgLocations)));
1197 newModuleAttrs.push_back(NamedAttribute(
1198 cache.sPortAnnotations,
builder->getArrayAttr(newArgAnnotations)));
1201 module->setAttrs(newModuleAttrs);
1202 module.setPortSymbols(newArgSyms);
1207 bool TypeLoweringVisitor::visitDecl(WireOp op) {
1208 if (op.isForceable())
1211 auto clone = [&](
const FlatBundleFieldEntry &field,
1212 ArrayAttr attrs) -> Value {
1214 ->create<WireOp>(
mapLoweredType(op.getDataRaw().getType(), field.type),
1215 "", NameKindEnum::DroppableName, attrs, StringAttr{})
1218 return lowerProducer(op, clone);
1222 bool TypeLoweringVisitor::visitDecl(RegOp op) {
1223 if (op.isForceable())
1226 auto clone = [&](
const FlatBundleFieldEntry &field,
1227 ArrayAttr attrs) -> Value {
1229 ->create<RegOp>(field.type, op.getClockVal(),
"",
1230 NameKindEnum::DroppableName, attrs, StringAttr{})
1233 return lowerProducer(op, clone);
1237 bool TypeLoweringVisitor::visitDecl(RegResetOp op) {
1238 if (op.isForceable())
1241 auto clone = [&](
const FlatBundleFieldEntry &field,
1242 ArrayAttr attrs) -> Value {
1243 auto resetVal = getSubWhatever(op.getResetValue(), field.index);
1245 ->create<RegResetOp>(field.type, op.getClockVal(), op.getResetSignal(),
1246 resetVal,
"", NameKindEnum::DroppableName, attrs,
1250 return lowerProducer(op, clone);
1254 bool TypeLoweringVisitor::visitDecl(NodeOp op) {
1255 if (op.isForceable())
1258 auto clone = [&](
const FlatBundleFieldEntry &field,
1259 ArrayAttr attrs) -> Value {
1260 auto input = getSubWhatever(op.getInput(), field.index);
1262 ->create<NodeOp>(input,
"", NameKindEnum::DroppableName, attrs)
1265 return lowerProducer(op, clone);
1269 bool TypeLoweringVisitor::visitExpr(InvalidValueOp op) {
1270 auto clone = [&](
const FlatBundleFieldEntry &field,
1271 ArrayAttr attrs) -> Value {
1272 return builder->create<InvalidValueOp>(field.type);
1274 return lowerProducer(op, clone);
1278 bool TypeLoweringVisitor::visitExpr(MuxPrimOp op) {
1279 auto clone = [&](
const FlatBundleFieldEntry &field,
1280 ArrayAttr attrs) -> Value {
1281 auto high = getSubWhatever(op.getHigh(), field.index);
1282 auto low = getSubWhatever(op.getLow(), field.index);
1283 return builder->create<MuxPrimOp>(op.getSel(), high, low);
1285 return lowerProducer(op, clone);
1289 bool TypeLoweringVisitor::visitExpr(Mux2CellIntrinsicOp op) {
1290 auto clone = [&](
const FlatBundleFieldEntry &field,
1291 ArrayAttr attrs) -> Value {
1292 auto high = getSubWhatever(op.getHigh(), field.index);
1293 auto low = getSubWhatever(op.getLow(), field.index);
1294 return builder->create<Mux2CellIntrinsicOp>(op.getSel(), high, low);
1296 return lowerProducer(op, clone);
1300 bool TypeLoweringVisitor::visitExpr(Mux4CellIntrinsicOp op) {
1301 auto clone = [&](
const FlatBundleFieldEntry &field,
1302 ArrayAttr attrs) -> Value {
1303 auto v3 = getSubWhatever(op.getV3(), field.index);
1304 auto v2 = getSubWhatever(op.getV2(), field.index);
1305 auto v1 = getSubWhatever(op.getV1(), field.index);
1306 auto v0 = getSubWhatever(op.getV0(), field.index);
1307 return builder->create<Mux4CellIntrinsicOp>(op.getSel(), v3, v2, v1, v0);
1309 return lowerProducer(op, clone);
1313 bool TypeLoweringVisitor::visitUnrealizedConversionCast(
1314 mlir::UnrealizedConversionCastOp op) {
1315 auto clone = [&](
const FlatBundleFieldEntry &field,
1316 ArrayAttr attrs) -> Value {
1317 auto input = getSubWhatever(op.getOperand(0), field.index);
1318 return builder->create<mlir::UnrealizedConversionCastOp>(field.type, input)
1323 if (!type_isa<FIRRTLType>(op->getOperand(0).getType()))
1325 return lowerProducer(op, clone);
1329 bool TypeLoweringVisitor::visitExpr(BitCastOp op) {
1330 Value srcLoweredVal = op.getInput();
1334 SmallVector<FlatBundleFieldEntry> fields;
1335 if (
peelType(op.getInput().getType(), fields, PreserveAggregate::None)) {
1336 size_t uptoBits = 0;
1339 for (
const auto &field : llvm::enumerate(fields)) {
1340 auto fieldBitwidth = *
getBitWidth(field.value().type);
1342 if (fieldBitwidth == 0)
1344 Value src = getSubWhatever(op.getInput(), field.index());
1346 src =
builder->createOrFold<BitCastOp>(
1350 srcLoweredVal = src;
1352 srcLoweredVal =
builder->create<CatPrimOp>(src, srcLoweredVal);
1354 uptoBits += fieldBitwidth;
1357 srcLoweredVal =
builder->createOrFold<AsUIntPrimOp>(srcLoweredVal);
1361 if (type_isa<BundleType, FVectorType>(op.getResult().getType())) {
1363 size_t uptoBits = 0;
1364 auto clone = [&](
const FlatBundleFieldEntry &field,
1365 ArrayAttr attrs) -> Value {
1371 return builder->create<InvalidValueOp>(field.type);
1376 srcLoweredVal, uptoBits + fieldBits - 1, uptoBits);
1377 uptoBits += fieldBits;
1380 return lowerProducer(op, clone);
1384 if (type_isa<SIntType>(op.getType()))
1385 srcLoweredVal =
builder->create<AsSIntPrimOp>(srcLoweredVal);
1386 op.getResult().replaceAllUsesWith(srcLoweredVal);
1390 bool TypeLoweringVisitor::visitExpr(RefSendOp op) {
1391 auto clone = [&](
const FlatBundleFieldEntry &field,
1392 ArrayAttr attrs) -> Value {
1393 return builder->create<RefSendOp>(
1394 getSubWhatever(op.getBase(), field.index));
1399 return lowerProducer(op, clone);
1402 bool TypeLoweringVisitor::visitExpr(RefResolveOp op) {
1403 auto clone = [&](
const FlatBundleFieldEntry &field,
1404 ArrayAttr attrs) -> Value {
1405 Value src = getSubWhatever(op.getRef(), field.index);
1406 return builder->create<RefResolveOp>(src);
1410 return lowerProducer(op, clone, op.getRef().getType());
1413 bool TypeLoweringVisitor::visitExpr(RefCastOp op) {
1414 auto clone = [&](
const FlatBundleFieldEntry &field,
1415 ArrayAttr attrs) -> Value {
1416 auto input = getSubWhatever(op.getInput(), field.index);
1418 op.getType().getForceable(),
1419 op.getType().getLayer()),
1422 return lowerProducer(op, clone);
1425 bool TypeLoweringVisitor::visitDecl(InstanceOp op) {
1427 SmallVector<Type, 8> resultTypes;
1428 SmallVector<int64_t, 8> endFields;
1429 auto oldPortAnno = op.getPortAnnotations();
1430 SmallVector<Direction> newDirs;
1431 SmallVector<Attribute> newNames;
1432 SmallVector<Attribute> newPortAnno;
1434 cast<FModuleLike>(op.getReferencedOperation(symTbl)));
1436 endFields.push_back(0);
1437 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
1438 auto srcType = type_cast<FIRRTLType>(op.getType(i));
1441 SmallVector<FlatBundleFieldEntry, 8> fieldTypes;
1442 if (!
peelType(srcType, fieldTypes, mode)) {
1443 newDirs.push_back(op.getPortDirection(i));
1444 newNames.push_back(op.getPortName(i));
1445 resultTypes.push_back(srcType);
1446 newPortAnno.push_back(oldPortAnno[i]);
1449 auto oldName = op.getPortNameStr(i);
1450 auto oldDir = op.getPortDirection(i);
1452 for (
const auto &field : fieldTypes) {
1453 newDirs.push_back(
direction::get((
unsigned)oldDir ^ field.isOutput));
1454 newNames.push_back(
builder->getStringAttr(oldName + field.suffix));
1456 auto annos = filterAnnotations(
1457 context, dyn_cast_or_null<ArrayAttr>(oldPortAnno[i]), srcType,
1459 newPortAnno.push_back(annos);
1462 endFields.push_back(resultTypes.size());
1472 auto newInstance =
builder->create<InstanceOp>(
1473 resultTypes, op.getModuleNameAttr(), op.getNameAttr(),
1475 builder->getArrayAttr(newNames), op.getAnnotations(),
1476 builder->getArrayAttr(newPortAnno), op.getLayersAttr(),
1477 op.getLowerToBindAttr(),
1482 auto attrNames = InstanceOp::getAttributeNames();
1483 DenseSet<StringRef> attrSet(attrNames.begin(), attrNames.end());
1484 SmallVector<NamedAttribute> newAttrs(newInstance->getAttrs());
1485 for (
auto i : llvm::make_filter_range(op->getAttrs(), [&](
auto namedAttr) {
1486 return !attrSet.count(namedAttr.getName());
1488 newAttrs.push_back(i);
1489 newInstance->setAttrs(newAttrs);
1491 SmallVector<Value> lowered;
1492 for (
size_t aggIndex = 0, eAgg = op.getNumResults(); aggIndex != eAgg;
1495 for (
size_t fieldIndex = endFields[aggIndex],
1496 eField = endFields[aggIndex + 1];
1497 fieldIndex < eField; ++fieldIndex)
1498 lowered.push_back(newInstance.getResult(fieldIndex));
1499 if (lowered.size() != 1 ||
1500 op.getType(aggIndex) != resultTypes[endFields[aggIndex]])
1501 processUsers(op.getResult(aggIndex), lowered);
1503 op.getResult(aggIndex).replaceAllUsesWith(lowered[0]);
1508 bool TypeLoweringVisitor::visitExpr(SubaccessOp op) {
1509 auto input = op.getInput();
1510 FVectorType vType = input.getType();
1513 if (vType.getNumElements() == 0) {
1514 Value inv =
builder->create<InvalidValueOp>(vType.getElementType());
1515 op.replaceAllUsesWith(inv);
1520 if (ConstantOp arg =
1521 llvm::dyn_cast_or_null<ConstantOp>(op.getIndex().getDefiningOp())) {
1522 auto sio =
builder->create<SubindexOp>(op.getInput(),
1523 arg.getValue().getExtValue());
1524 op.replaceAllUsesWith(sio.getResult());
1529 SmallVector<Value>
inputs;
1530 inputs.reserve(vType.getNumElements());
1531 for (
int index = vType.getNumElements() - 1; index >= 0; index--)
1532 inputs.push_back(
builder->create<SubindexOp>(input, index));
1534 Value multibitMux =
builder->create<MultibitMuxOp>(op.getIndex(),
inputs);
1535 op.replaceAllUsesWith(multibitMux);
1539 bool TypeLoweringVisitor::visitExpr(VectorCreateOp op) {
1540 auto clone = [&](
const FlatBundleFieldEntry &field,
1541 ArrayAttr attrs) -> Value {
1542 return op.getOperand(field.index);
1544 return lowerProducer(op, clone);
1547 bool TypeLoweringVisitor::visitExpr(BundleCreateOp op) {
1548 auto clone = [&](
const FlatBundleFieldEntry &field,
1549 ArrayAttr attrs) -> Value {
1550 return op.getOperand(field.index);
1552 return lowerProducer(op, clone);
1555 bool TypeLoweringVisitor::visitExpr(ElementwiseOrPrimOp op) {
1556 auto clone = [&](
const FlatBundleFieldEntry &field,
1557 ArrayAttr attrs) -> Value {
1558 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1559 getSubWhatever(op.getRhs(), field.index)};
1560 return type_isa<BundleType, FVectorType>(field.type)
1561 ? (Value)
builder->create<ElementwiseOrPrimOp>(field.type,
1563 : (Value)
builder->create<OrPrimOp>(operands);
1566 return lowerProducer(op, clone);
1569 bool TypeLoweringVisitor::visitExpr(ElementwiseAndPrimOp op) {
1570 auto clone = [&](
const FlatBundleFieldEntry &field,
1571 ArrayAttr attrs) -> Value {
1572 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1573 getSubWhatever(op.getRhs(), field.index)};
1574 return type_isa<BundleType, FVectorType>(field.type)
1575 ? (Value)
builder->create<ElementwiseAndPrimOp>(field.type,
1577 : (Value)
builder->create<AndPrimOp>(operands);
1580 return lowerProducer(op, clone);
1583 bool TypeLoweringVisitor::visitExpr(ElementwiseXorPrimOp op) {
1584 auto clone = [&](
const FlatBundleFieldEntry &field,
1585 ArrayAttr attrs) -> Value {
1586 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1587 getSubWhatever(op.getRhs(), field.index)};
1588 return type_isa<BundleType, FVectorType>(field.type)
1589 ? (Value)
builder->create<ElementwiseXorPrimOp>(field.type,
1591 : (Value)
builder->create<XorPrimOp>(operands);
1594 return lowerProducer(op, clone);
1597 bool TypeLoweringVisitor::visitExpr(MultibitMuxOp op) {
1598 auto clone = [&](
const FlatBundleFieldEntry &field,
1599 ArrayAttr attrs) -> Value {
1600 SmallVector<Value> newInputs;
1601 newInputs.reserve(op.getInputs().size());
1602 for (
auto input : op.getInputs()) {
1603 auto inputSub = getSubWhatever(input, field.index);
1604 newInputs.push_back(inputSub);
1606 return builder->create<MultibitMuxOp>(op.getIndex(), newInputs);
1608 return lowerProducer(op, clone);
1616 struct LowerTypesPass :
public LowerFIRRTLTypesBase<LowerTypesPass> {
1620 preserveAggregate = preserveAggregateFlag;
1621 preserveMemories = preserveMemoriesFlag;
1623 void runOnOperation()
override;
1628 void LowerTypesPass::runOnOperation() {
1630 std::vector<FModuleLike> ops;
1632 auto &symTbl = getAnalysis<SymbolTable>();
1634 AttrCache cache(&getContext());
1636 DenseMap<FModuleLike, Convention> conventionTable;
1637 auto circuit = getOperation();
1638 for (
auto module : circuit.getOps<FModuleLike>()) {
1639 conventionTable.insert({module, module.getConvention()});
1640 ops.push_back(module);
1644 auto lowerModules = [&](FModuleLike op) -> LogicalResult {
1646 TypeLoweringVisitor(&getContext(), preserveAggregate, preserveMemories,
1647 symTbl, cache, conventionTable);
1650 return LogicalResult::failure(tl.isFailed());
1653 auto result = failableParallelForEach(&getContext(), ops, lowerModules);
1656 signalPassFailure();
1663 return std::make_unique<LowerTypesPass>(mode, memoryMode);
assert(baseType &&"element must be base type")
static void dump(DIModule &module, raw_indented_ostream &os)
static Value extractBits(OpBuilder &builder, Location loc, Value value, unsigned startBit, unsigned bitWidth)
static bool isPreservableAggregateType(Type type, PreserveAggregate::PreserveMode mode)
Return true if we can preserve the type.
static SmallVector< Operation * > getSAWritePath(Operation *op)
Look through and collect subfields leading to a subaccess.
static FIRRTLType mapLoweredType(FIRRTLType type, FIRRTLBaseType fieldType)
Return fieldType or fieldType as same ref as type.
static MemOp cloneMemWithNewType(ImplicitLocOpBuilder *b, MemOp op, FlatBundleFieldEntry field)
Clone memory for the specified field. Returns null op on error.
static bool containsBundleType(FIRRTLType type)
Return true if the type has a bundle type as subtype.
static Value cloneAccess(ImplicitLocOpBuilder *builder, Operation *op, Value rhs)
static bool peelType(Type type, SmallVectorImpl< FlatBundleFieldEntry > &fields, PreserveAggregate::PreserveMode mode)
Peel one layer of an aggregate type into its components.
static bool isNotSubAccess(Operation *op)
Return if something is not a normal subaccess.
static bool isOneDimVectorType(FIRRTLType type)
Return true if the type is a 1d vector type or ground type.
llvm::SmallVector< StringAttr > inputs
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
This class provides a read-only projection of an annotation.
DictionaryAttr getDict() const
Get the data dictionary of this attribute.
unsigned getFieldID() const
Get the field id this attribute targets.
void setMember(StringAttr name, Attribute value)
Add or set a member of the annotation to a value.
This class implements the same functionality as TypeSwitch except that it uses firrtl::type_dyn_cast ...
FIRRTLTypeSwitch< T, ResultT > & Case(CallableT &&caseFn)
Add a case on the given type.
FIRRTLVisitor allows you to visit all of the expr/stmt/decls with one class declaration.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
IntegerAttr packAttribute(MLIRContext *context, size_t nIns, size_t nOuts)
Returns an IntegerAttr containing the packed representation of the direction counts.
@ All
Preserve all aggregate values.
@ OneDimVec
Preserve only 1d vectors of ground type (e.g. UInt<2>[3]).
@ Vec
Preserve only vectors (e.g. UInt<2>[3][3]).
@ None
Don't preserve aggregate at all.
mlir::DenseBoolArrayAttr packAttribute(MLIRContext *context, ArrayRef< Direction > directions)
Return a DenseBoolArrayAttr containing the packed representation of an array of directions.
Direction
This represents the direction of a single port.
FIRRTLBaseType getBaseType(Type type)
If it is a base type, return it as is.
FIRRTLType mapBaseType(FIRRTLType type, function_ref< FIRRTLBaseType(FIRRTLBaseType)> fn)
Return a FIRRTLType with its base type component mutated by the given function.
std::unique_ptr< mlir::Pass > createLowerFIRRTLTypesPass(PreserveAggregate::PreserveMode mode=PreserveAggregate::None, PreserveAggregate::PreserveMode memoryMode=PreserveAggregate::None)
This is the pass constructor.
bool hasZeroBitWidth(FIRRTLType type)
Return true if the type has zero bit width.
void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs)
Emit a connect between two values.
StringAttr getInnerSymName(Operation *op)
Return the StringAttr for the inner_sym name, if it exists.
std::optional< int64_t > getBitWidth(FIRRTLBaseType type, bool ignoreFlip=false)
uint64_t getMaxFieldID(Type)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
llvm::raw_ostream & debugPassHeader(const mlir::Pass *pass, int width=80)
Write a boilerplate header for a pass to the debug stream.
This holds the name and type that describes the module's ports.