32 #include "mlir/Pass/Pass.h"
47 #include "mlir/IR/ImplicitLocOpBuilder.h"
48 #include "mlir/IR/Threading.h"
49 #include "llvm/ADT/APSInt.h"
50 #include "llvm/ADT/BitVector.h"
51 #include "llvm/Support/Debug.h"
52 #include "llvm/Support/Parallel.h"
54 #define DEBUG_TYPE "firrtl-lower-types"
58 #define GEN_PASS_DEF_LOWERFIRRTLTYPES
59 #include "circt/Dialect/FIRRTL/Passes.h.inc"
63 using namespace circt;
64 using namespace firrtl;
69 struct FlatBundleFieldEntry {
77 SmallString<16> suffix;
82 unsigned fieldID, StringRef suffix,
bool isOutput)
83 : type(type), index(index), fieldID(fieldID), suffix(suffix),
87 llvm::errs() <<
"FBFE{" << type <<
" index<" << index <<
"> fieldID<"
88 << fieldID <<
"> suffix<" << suffix <<
"> isOutput<"
89 << isOutput <<
">}\n";
94 struct PortInfoWithIP {
96 std::optional<InternalPathAttr> internalPath;
103 return mapBaseType(type, [&](
auto) {
return fieldType; });
108 auto ftype = type_dyn_cast<FIRRTLType>(type);
117 .
Case<BundleType>([&](
auto bundle) {
return false; })
118 .Case<FVectorType>([&](FVectorType vector) {
120 return vector.getElementType().isGround() &&
121 vector.getNumElements() > 1;
123 .Default([](
auto groundType) {
return true; });
130 .
Case<BundleType>([&](
auto bundle) {
return true; })
131 .Case<FVectorType>([&](FVectorType vector) {
134 .Default([](
auto groundType) {
return false; });
141 if (
auto refType = type_dyn_cast<RefType>(type)) {
143 if (refType.getForceable())
154 auto firrtlType = type_dyn_cast<FIRRTLBaseType>(type);
160 if (!firrtlType.isPassive() || firrtlType.containsAnalog() ||
172 llvm_unreachable(
"unexpected mode");
178 static bool peelType(Type type, SmallVectorImpl<FlatBundleFieldEntry> &fields,
185 if (
auto refType = type_dyn_cast<RefType>(type))
186 type = refType.getType();
188 .
Case<BundleType>([&](
auto bundle) {
189 SmallString<16> tmpSuffix;
191 for (
size_t i = 0, e = bundle.getNumElements(); i < e; ++i) {
192 auto elt = bundle.getElement(i);
195 tmpSuffix.push_back(
'_');
196 tmpSuffix.append(elt.name.getValue());
197 fields.emplace_back(elt.type, i, bundle.getFieldID(i), tmpSuffix,
202 .Case<FVectorType>([&](
auto vector) {
204 for (
size_t i = 0, e = vector.getNumElements(); i != e; ++i) {
205 fields.emplace_back(vector.getElementType(), i, vector.getFieldID(i),
206 "_" + std::to_string(i),
false);
210 .Default([](
auto op) {
return false; });
216 SubaccessOp sao = llvm::dyn_cast<SubaccessOp>(op);
220 llvm::dyn_cast_or_null<ConstantOp>(sao.getIndex().getDefiningOp());
221 return arg && sao.getInput().getType().base().getNumElements() != 0;
226 SmallVector<Operation *> retval;
227 auto defOp = op->getOperand(0).getDefiningOp();
228 while (isa_and_nonnull<SubfieldOp, SubindexOp, SubaccessOp>(defOp)) {
229 retval.push_back(defOp);
230 defOp = defOp->getOperand(0).getDefiningOp();
240 FlatBundleFieldEntry field) {
241 SmallVector<Type, 8> ports;
242 SmallVector<Attribute, 8> portNames;
243 SmallVector<Attribute, 8> portLocations;
245 auto oldPorts = op.getPorts();
246 for (
size_t portIdx = 0, e = oldPorts.size(); portIdx < e; ++portIdx) {
247 auto port = oldPorts[portIdx];
249 MemOp::getTypeForPort(op.getDepth(), field.type, port.second));
250 portNames.push_back(port.first);
254 auto newMem = b->create<MemOp>(
255 ports, op.getReadLatency(), op.getWriteLatency(), op.getDepth(),
256 op.getRuw(), portNames, (op.getName() + field.suffix).str(),
257 op.getNameKind(), op.getAnnotations().getValue(),
258 op.getPortAnnotations().getValue(), op.getInnerSymAttr());
260 if (op.getInnerSym()) {
261 op.emitError(
"cannot split memory with symbol present");
265 SmallVector<Attribute> newAnnotations;
266 for (
size_t portIdx = 0, e = newMem.getNumResults(); portIdx < e; ++portIdx) {
267 auto portType = type_cast<BundleType>(newMem.getResult(portIdx).getType());
268 auto oldPortType = type_cast<BundleType>(op.getResult(portIdx).getType());
269 SmallVector<Attribute> portAnno;
270 for (
auto attr : newMem.getPortAnnotation(portIdx)) {
273 auto targetIndex = oldPortType.getIndexForFieldID(annoFieldID);
277 if (annoFieldID == oldPortType.getFieldID(targetIndex)) {
280 b->getI32IntegerAttr(portType.getFieldID(targetIndex)));
281 portAnno.push_back(anno.
getDict());
286 if (type_isa<BundleType>(oldPortType.getElement(targetIndex).type)) {
291 auto fieldID = field.fieldID + oldPortType.getFieldID(targetIndex);
292 if (annoFieldID >= fieldID &&
297 annoFieldID - fieldID + portType.getFieldID(targetIndex);
298 anno.
setMember(
"circt.fieldID", b->getI32IntegerAttr(newFieldID));
299 portAnno.push_back(anno.
getDict());
303 portAnno.push_back(attr);
305 newAnnotations.push_back(b->getArrayAttr(portAnno));
307 newMem.setAllPortAnnotations(newAnnotations);
317 AttrCache(MLIRContext *context) {
329 AttrCache(
const AttrCache &) =
default;
332 StringAttr nameAttr, nameKindAttr, sPortDirections, sPortNames, sPortTypes,
333 sPortSyms, sPortLocations, sPortAnnotations, sEmpty;
338 struct TypeLoweringVisitor :
public FIRRTLVisitor<TypeLoweringVisitor, bool> {
343 SymbolTable &symTbl,
const AttrCache &cache,
344 const llvm::DenseMap<FModuleLike, Convention> &conventionTable)
345 : context(context), aggregatePreservationMode(preserveAggregate),
346 memoryPreservationMode(memoryPreservationMode), symTbl(symTbl),
347 cache(cache), conventionTable(conventionTable) {}
354 void lowerModule(FModuleLike op);
356 bool lowerArg(FModuleLike module,
size_t argIndex,
size_t argsRemoved,
357 SmallVectorImpl<PortInfoWithIP> &newArgs,
358 SmallVectorImpl<Value> &lowering);
359 std::pair<Value, PortInfoWithIP>
360 addArg(Operation *module,
unsigned insertPt,
unsigned insertPtOffset,
361 FIRRTLType srcType,
const FlatBundleFieldEntry &field,
362 PortInfoWithIP &oldArg, hw::InnerSymAttr newSym);
365 bool visitDecl(FExtModuleOp op);
366 bool visitDecl(FModuleOp op);
367 bool visitDecl(InstanceOp op);
368 bool visitDecl(MemOp op);
369 bool visitDecl(NodeOp op);
370 bool visitDecl(RegOp op);
371 bool visitDecl(WireOp op);
372 bool visitDecl(RegResetOp op);
373 bool visitExpr(InvalidValueOp op);
374 bool visitExpr(SubaccessOp op);
375 bool visitExpr(VectorCreateOp op);
376 bool visitExpr(BundleCreateOp op);
377 bool visitExpr(ElementwiseAndPrimOp op);
378 bool visitExpr(ElementwiseOrPrimOp op);
379 bool visitExpr(ElementwiseXorPrimOp op);
380 bool visitExpr(MultibitMuxOp op);
381 bool visitExpr(MuxPrimOp op);
382 bool visitExpr(Mux2CellIntrinsicOp op);
383 bool visitExpr(Mux4CellIntrinsicOp op);
384 bool visitExpr(BitCastOp op);
385 bool visitExpr(RefSendOp op);
386 bool visitExpr(RefResolveOp op);
387 bool visitExpr(RefCastOp op);
388 bool visitStmt(ConnectOp op);
389 bool visitStmt(MatchingConnectOp op);
390 bool visitStmt(RefDefineOp op);
391 bool visitStmt(WhenOp op);
392 bool visitStmt(LayerBlockOp op);
393 bool visitUnrealizedConversionCast(mlir::UnrealizedConversionCastOp op);
395 bool isFailed()
const {
return encounteredError; }
397 bool visitInvalidOp(Operation *op) {
398 if (
auto castOp = dyn_cast<mlir::UnrealizedConversionCastOp>(op))
399 return visitUnrealizedConversionCast(castOp);
404 void processUsers(Value val, ArrayRef<Value> mapping);
405 bool processSAPath(Operation *);
406 void lowerBlock(Block *);
407 void lowerSAWritePath(Operation *, ArrayRef<Operation *> writePath);
417 llvm::function_ref<Value(
const FlatBundleFieldEntry &, ArrayAttr)> clone,
422 ArrayAttr filterAnnotations(MLIRContext *
ctxt, ArrayAttr annotations,
423 FIRRTLType srcType, FlatBundleFieldEntry field);
427 LogicalResult partitionSymbols(hw::InnerSymAttr sym,
FIRRTLType parentType,
428 SmallVectorImpl<hw::InnerSymAttr> &newSyms,
432 getPreservationModeForModule(FModuleLike moduleLike);
433 Value getSubWhatever(Value val,
size_t index);
435 size_t uniqueIdx = 0;
436 std::string uniqueName() {
437 auto myID = uniqueIdx++;
438 return (Twine(
"__GEN_") + Twine(myID)).str();
441 MLIRContext *context;
448 ImplicitLocOpBuilder *builder;
454 const AttrCache &cache;
456 const llvm::DenseMap<FModuleLike, Convention> &conventionTable;
459 bool encounteredError =
false;
466 TypeLoweringVisitor::getPreservationModeForModule(FModuleLike module) {
467 auto lookup = conventionTable.find(module);
468 if (lookup == conventionTable.end())
469 return aggregatePreservationMode;
470 switch (lookup->second) {
471 case Convention::Scalarized:
473 case Convention::Internal:
474 return aggregatePreservationMode;
476 llvm_unreachable(
"Unknown convention");
477 return aggregatePreservationMode;
480 Value TypeLoweringVisitor::getSubWhatever(Value val,
size_t index) {
481 if (type_isa<BundleType>(val.getType()))
482 return builder->create<SubfieldOp>(val, index);
483 if (type_isa<FVectorType>(val.getType()))
484 return builder->create<SubindexOp>(val, index);
485 if (type_isa<RefType>(val.getType()))
486 return builder->create<RefSubOp>(val, index);
487 llvm_unreachable(
"Unknown aggregate type");
492 bool TypeLoweringVisitor::processSAPath(Operation *op) {
495 if (writePath.empty())
498 lowerSAWritePath(op, writePath);
501 op->eraseOperands(0, 2);
503 for (
size_t i = 0; i < writePath.size(); ++i) {
504 if (writePath[i]->use_empty()) {
505 writePath[i]->erase();
513 void TypeLoweringVisitor::lowerBlock(Block *block) {
515 for (
auto it = block->rbegin(), e = block->rend(); it != e;) {
517 builder->setInsertionPoint(&iop);
518 builder->setLoc(iop.getLoc());
519 bool removeOp = dispatchVisitor(&iop);
528 ArrayAttr TypeLoweringVisitor::filterAnnotations(MLIRContext *
ctxt,
529 ArrayAttr annotations,
531 FlatBundleFieldEntry field) {
532 SmallVector<Attribute> retval;
533 if (!annotations || annotations.empty())
535 for (
auto opAttr : annotations) {
537 auto fieldID = anno.getFieldID();
538 anno.removeMember(
"circt.fieldID");
543 retval.push_back(anno.getAttr());
548 if (fieldID < field.fieldID ||
553 if (
auto newFieldID = fieldID - field.fieldID) {
556 anno.setMember(
"circt.fieldID", builder->getI32IntegerAttr(newFieldID));
559 retval.push_back(anno.getAttr());
564 LogicalResult TypeLoweringVisitor::partitionSymbols(
566 SmallVectorImpl<hw::InnerSymAttr> &newSyms, Location errorLoc) {
569 if (!sym || sym.empty())
572 auto *context = sym.getContext();
576 return mlir::emitError(errorLoc,
577 "unable to partition symbol on unsupported type ")
580 return TypeSwitch<FIRRTLType, LogicalResult>(baseType)
581 .Case<BundleType, FVectorType>([&](
auto aggType) -> LogicalResult {
585 hw::InnerSymPropertiesAttr prop;
589 SmallVector<BinningInfo> binning;
590 for (
auto prop : sym) {
591 auto fieldID = prop.getFieldID();
594 return mlir::emitError(errorLoc,
"unable to lower due to symbol ")
596 <<
" with target not preserved by lowering";
597 auto [index, relFieldID] = aggType.getIndexAndSubfieldID(fieldID);
598 binning.push_back({index, relFieldID, prop});
602 llvm::stable_sort(binning, [&](
auto &lhs,
auto &rhs) {
603 return std::tuple(lhs.index, lhs.relFieldID) <
604 std::tuple(rhs.index, rhs.relFieldID);
609 newSyms.resize(aggType.getNumElements());
610 for (
auto binIt = binning.begin(), binEnd = binning.end();
612 auto curIndex = binIt->index;
613 SmallVector<hw::InnerSymPropertiesAttr> propsForIndex;
615 while (binIt != binEnd && binIt->index == curIndex) {
617 context, binIt->prop.getName(), binIt->relFieldID,
618 binIt->prop.getSymVisibility()));
622 assert(!newSyms[curIndex]);
627 .Default([&](
auto ty) {
628 return mlir::emitError(
629 errorLoc,
"unable to partition symbol on unsupported type ")
634 bool TypeLoweringVisitor::lowerProducer(
636 llvm::function_ref<Value(
const FlatBundleFieldEntry &, ArrayAttr)> clone,
640 srcType = op->getResult(0).getType();
641 auto srcFType = type_dyn_cast<FIRRTLType>(srcType);
644 SmallVector<FlatBundleFieldEntry, 8> fieldTypes;
646 if (!
peelType(srcFType, fieldTypes, aggregatePreservationMode))
649 SmallVector<Value> lowered;
651 SmallString<16> loweredName;
652 auto nameKindAttr = op->getAttrOfType<NameKindEnumAttr>(cache.nameKindAttr);
654 if (
auto nameAttr = op->getAttrOfType<StringAttr>(cache.nameAttr))
655 loweredName = nameAttr.getValue();
656 auto baseNameLen = loweredName.size();
657 auto oldAnno = dyn_cast_or_null<ArrayAttr>(op->getAttr(
"annotations"));
659 SmallVector<hw::InnerSymAttr> fieldSyms(fieldTypes.size());
660 if (
auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(op)) {
661 if (failed(partitionSymbols(symOp.getInnerSymAttr(), srcFType, fieldSyms,
663 encounteredError =
true;
668 for (
const auto &[field, sym] : llvm::zip_equal(fieldTypes, fieldSyms)) {
669 if (!loweredName.empty()) {
670 loweredName.resize(baseNameLen);
671 loweredName += field.suffix;
676 ArrayAttr loweredAttrs =
677 filterAnnotations(context, oldAnno, srcFType, field);
678 auto newVal = clone(field, loweredAttrs);
684 auto newSymOp = newVal.getDefiningOp<hw::InnerSymbolOpInterface>();
687 "op with inner symbol lowered to op that cannot take inner symbol");
688 newSymOp.setInnerSymbolAttr(sym);
692 if (
auto *newOp = newVal.getDefiningOp()) {
693 if (!loweredName.empty())
696 newOp->setAttr(cache.nameKindAttr, nameKindAttr);
698 lowered.push_back(newVal);
701 processUsers(op->getResult(0), lowered);
705 void TypeLoweringVisitor::processUsers(Value val, ArrayRef<Value> mapping) {
706 for (
auto *user : llvm::make_early_inc_range(val.getUsers())) {
707 TypeSwitch<Operation *, void>(user)
708 .Case<SubindexOp>([mapping](SubindexOp sio) {
709 Value repl = mapping[sio.getIndex()];
710 sio.replaceAllUsesWith(repl);
713 .Case<SubfieldOp>([mapping](SubfieldOp sfo) {
715 Value repl = mapping[sfo.getFieldIndex()];
716 sfo.replaceAllUsesWith(repl);
719 .Case<RefSubOp>([mapping](RefSubOp refSub) {
720 Value repl = mapping[refSub.getIndex()];
721 refSub.replaceAllUsesWith(repl);
724 .Default([&](
auto op) {
735 ImplicitLocOpBuilder b(user->getLoc(), user);
739 assert(llvm::none_of(mapping, [](
auto v) {
740 auto fbasetype = type_dyn_cast<FIRRTLBaseType>(v.getType());
741 return !fbasetype || fbasetype.containsReference();
745 TypeSwitch<Type, Value>(val.getType())
746 .template Case<FVectorType>([&](
auto vecType) {
747 return b.createOrFold<VectorCreateOp>(vecType, mapping);
749 .
template Case<BundleType>([&](
auto bundleType) {
750 return b.createOrFold<BundleCreateOp>(bundleType, mapping);
752 .Default([&](
auto _) -> Value {
return {}; });
754 user->emitError(
"unable to reconstruct source of type ")
756 encounteredError =
true;
759 user->replaceUsesOfWith(val, input);
764 void TypeLoweringVisitor::lowerModule(FModuleLike op) {
765 if (
auto module = llvm::dyn_cast<FModuleOp>(*op))
767 else if (
auto extModule = llvm::dyn_cast<FExtModuleOp>(*op))
768 visitDecl(extModule);
774 std::pair<Value, PortInfoWithIP>
775 TypeLoweringVisitor::addArg(Operation *module,
unsigned insertPt,
777 const FlatBundleFieldEntry &field,
778 PortInfoWithIP &oldArg, hw::InnerSymAttr newSym) {
781 if (
auto mod = llvm::dyn_cast<FModuleOp>(module)) {
782 Block *body = mod.getBodyBlock();
784 newValue = body->insertArgument(insertPt, fieldType, oldArg.pi.loc);
788 auto name = builder->getStringAttr(oldArg.pi.name.getValue() + field.suffix);
791 auto newAnnotations = filterAnnotations(
792 context, oldArg.pi.annotations.getArrayAttr(), srcType, field);
794 auto direction = (
Direction)((
unsigned)oldArg.pi.direction ^ field.isOutput);
796 return std::make_pair(
798 PortInfoWithIP{
PortInfo{name, fieldType, direction, newSym, oldArg.pi.loc,
800 oldArg.internalPath});
804 bool TypeLoweringVisitor::lowerArg(FModuleLike module,
size_t argIndex,
806 SmallVectorImpl<PortInfoWithIP> &newArgs,
807 SmallVectorImpl<Value> &lowering) {
810 SmallVector<FlatBundleFieldEntry> fieldTypes;
811 auto srcType = type_cast<FIRRTLType>(newArgs[argIndex].pi.type);
812 if (!
peelType(srcType, fieldTypes, getPreservationModeForModule(module)))
816 if (
auto ip = newArgs[argIndex].internalPath; ip && ip->getPath()) {
817 ::mlir::emitError(newArgs[argIndex].pi.loc,
818 "cannot lower port with internal path");
819 encounteredError =
true;
823 SmallVector<hw::InnerSymAttr> fieldSyms(fieldTypes.size());
824 if (failed(partitionSymbols(newArgs[argIndex].pi.sym, srcType, fieldSyms,
825 newArgs[argIndex].pi.loc))) {
826 encounteredError =
true;
830 for (
const auto &[idx, field, fieldSym] :
831 llvm::enumerate(fieldTypes, fieldSyms)) {
832 auto newValue = addArg(module, 1 + argIndex + idx, argsRemoved, srcType,
833 field, newArgs[argIndex], fieldSym);
834 newArgs.insert(newArgs.begin() + 1 + argIndex + idx, newValue.second);
836 lowering.push_back(newValue.first);
841 static Value
cloneAccess(ImplicitLocOpBuilder *builder, Operation *op,
843 if (
auto rop = llvm::dyn_cast<SubfieldOp>(op))
844 return builder->create<SubfieldOp>(rhs, rop.getFieldIndex());
845 if (
auto rop = llvm::dyn_cast<SubindexOp>(op))
846 return builder->create<SubindexOp>(rhs, rop.getIndex());
847 if (
auto rop = llvm::dyn_cast<SubaccessOp>(op))
848 return builder->create<SubaccessOp>(rhs, rop.getIndex());
849 op->emitError(
"Unknown accessor");
853 void TypeLoweringVisitor::lowerSAWritePath(Operation *op,
854 ArrayRef<Operation *> writePath) {
855 SubaccessOp sao = cast<SubaccessOp>(writePath.back());
856 FVectorType saoType = sao.getInput().getType();
857 auto selectWidth = llvm::Log2_64_Ceil(saoType.getNumElements());
859 for (
size_t index = 0, e = saoType.getNumElements(); index < e; ++index) {
860 auto cond = builder->create<EQPrimOp>(
862 builder->createOrFold<ConstantOp>(
UIntType::get(context, selectWidth),
863 APInt(selectWidth, index)));
864 builder->create<WhenOp>(cond,
false, [&]() {
866 Value leaf = builder->create<SubindexOp>(sao.getInput(), index);
867 for (
int i = writePath.size() - 2; i >= 0; --i) {
868 if (
auto access =
cloneAccess(builder, writePath[i], leaf))
871 encounteredError =
true;
882 bool TypeLoweringVisitor::visitStmt(ConnectOp op) {
883 if (processSAPath(op))
887 SmallVector<FlatBundleFieldEntry> fields;
894 for (
const auto &field : llvm::enumerate(fields)) {
895 Value src = getSubWhatever(op.getSrc(), field.index());
896 Value dest = getSubWhatever(op.getDest(), field.index());
897 if (field.value().isOutput)
898 std::swap(src, dest);
905 bool TypeLoweringVisitor::visitStmt(MatchingConnectOp op) {
906 if (processSAPath(op))
910 SmallVector<FlatBundleFieldEntry> fields;
917 for (
const auto &field : llvm::enumerate(fields)) {
918 Value src = getSubWhatever(op.getSrc(), field.index());
919 Value dest = getSubWhatever(op.getDest(), field.index());
920 if (field.value().isOutput)
921 std::swap(src, dest);
922 builder->create<MatchingConnectOp>(dest, src);
928 bool TypeLoweringVisitor::visitStmt(RefDefineOp op) {
930 SmallVector<FlatBundleFieldEntry> fields;
932 if (!
peelType(op.getDest().getType(), fields, aggregatePreservationMode))
936 for (
const auto &field : llvm::enumerate(fields)) {
937 Value src = getSubWhatever(op.getSrc(), field.index());
938 Value dest = getSubWhatever(op.getDest(), field.index());
939 assert(!field.value().isOutput &&
"unexpected flip in reftype destination");
940 builder->create<RefDefineOp>(dest, src);
945 bool TypeLoweringVisitor::visitStmt(WhenOp op) {
951 lowerBlock(&op.getThenBlock());
954 if (op.hasElseRegion())
955 lowerBlock(&op.getElseBlock());
960 bool TypeLoweringVisitor::visitStmt(LayerBlockOp op) {
961 lowerBlock(op.getBody());
967 bool TypeLoweringVisitor::visitDecl(MemOp op) {
969 SmallVector<FlatBundleFieldEntry> fields;
972 if (!
peelType(op.getDataType(), fields, memoryPreservationMode))
975 if (op.getInnerSym()) {
976 op->emitError() <<
"has a symbol, but no symbols may exist on aggregates "
977 "passed through LowerTypes";
978 encounteredError =
true;
982 SmallVector<MemOp> newMemories;
983 SmallVector<WireOp> oldPorts;
986 for (
unsigned int index = 0, end = op.getNumResults(); index < end; ++index) {
987 auto result = op.getResult(index);
988 if (op.getPortKind(index) == MemOp::PortKind::Debug) {
989 op.emitOpError(
"cannot lower memory with debug port");
990 encounteredError =
true;
993 auto wire = builder->create<WireOp>(
995 (op.getName() +
"_" + op.getPortName(index).getValue()).str());
996 oldPorts.push_back(wire);
997 result.replaceAllUsesWith(wire.getResult());
1004 for (
const auto &field : fields) {
1006 if (!newMemForField) {
1007 op.emitError(
"failed cloning memory for field");
1008 encounteredError =
true;
1011 newMemories.push_back(newMemForField);
1014 for (
size_t index = 0, rend = op.getNumResults(); index < rend; ++index) {
1015 auto result = oldPorts[index].getResult();
1016 auto rType = type_cast<BundleType>(result.getType());
1017 for (
size_t fieldIndex = 0, fend = rType.getNumElements();
1018 fieldIndex != fend; ++fieldIndex) {
1019 auto name = rType.getElement(fieldIndex).name.getValue();
1020 auto oldField = builder->create<SubfieldOp>(result, fieldIndex);
1023 if (name ==
"data" || name ==
"mask" || name ==
"wdata" ||
1024 name ==
"wmask" || name ==
"rdata") {
1025 for (
const auto &field : fields) {
1026 auto realOldField = getSubWhatever(oldField, field.index);
1027 auto newField = getSubWhatever(
1028 newMemories[field.index].getResult(index), fieldIndex);
1029 if (rType.getElement(fieldIndex).isFlip)
1030 std::swap(realOldField, newField);
1034 for (
auto mem : newMemories) {
1036 builder->create<SubfieldOp>(mem.getResult(index), fieldIndex);
1045 bool TypeLoweringVisitor::visitDecl(FExtModuleOp extModule) {
1046 ImplicitLocOpBuilder theBuilder(extModule.getLoc(), context);
1047 builder = &theBuilder;
1050 OpBuilder builder(context);
1052 auto internalPaths = extModule.getInternalPaths();
1055 SmallVector<unsigned> argsToRemove;
1056 SmallVector<PortInfoWithIP> newArgs;
1057 for (
auto [idx, pi] : llvm::enumerate(extModule.getPorts())) {
1058 std::optional<InternalPathAttr> internalPath;
1060 internalPath = cast<InternalPathAttr>(internalPaths->getValue()[idx]);
1061 newArgs.push_back({pi, internalPath});
1064 for (
size_t argIndex = 0, argsRemoved = 0; argIndex < newArgs.size();
1066 SmallVector<Value> lowering;
1067 if (lowerArg(extModule, argIndex, argsRemoved, newArgs, lowering)) {
1068 argsToRemove.push_back(argIndex);
1075 for (
auto toRemove : llvm::reverse(argsToRemove))
1076 newArgs.erase(newArgs.begin() + toRemove);
1078 SmallVector<NamedAttribute, 8> newModuleAttrs;
1081 for (
auto attr : extModule->getAttrDictionary())
1084 if (attr.getName() !=
"portDirections" && attr.getName() !=
"portNames" &&
1085 attr.getName() !=
"portTypes" && attr.getName() !=
"portAnnotations" &&
1086 attr.getName() !=
"portSyms" && attr.getName() !=
"portLocations")
1087 newModuleAttrs.push_back(attr);
1089 SmallVector<Direction> newArgDirections;
1090 SmallVector<Attribute> newArgNames;
1091 SmallVector<Attribute, 8> newArgTypes;
1092 SmallVector<Attribute, 8> newArgSyms;
1093 SmallVector<Attribute, 8> newArgLocations;
1094 SmallVector<Attribute, 8> newArgAnnotations;
1095 SmallVector<Attribute, 8> newInternalPaths;
1098 for (
auto &port : newArgs) {
1099 newArgDirections.push_back(port.pi.direction);
1100 newArgNames.push_back(port.pi.name);
1102 newArgSyms.push_back(port.pi.sym);
1103 newArgLocations.push_back(port.pi.loc);
1104 newArgAnnotations.push_back(port.pi.annotations.getArrayAttr());
1106 newInternalPaths.push_back(port.internalPath.value_or(emptyInternalPath));
1109 newModuleAttrs.push_back(
1110 NamedAttribute(cache.sPortDirections,
1113 newModuleAttrs.push_back(
1114 NamedAttribute(cache.sPortNames, builder.getArrayAttr(newArgNames)));
1116 newModuleAttrs.push_back(
1117 NamedAttribute(cache.sPortTypes, builder.getArrayAttr(newArgTypes)));
1119 newModuleAttrs.push_back(NamedAttribute(
1120 cache.sPortLocations, builder.getArrayAttr(newArgLocations)));
1122 newModuleAttrs.push_back(NamedAttribute(
1123 cache.sPortAnnotations, builder.getArrayAttr(newArgAnnotations)));
1126 extModule->setAttrs(newModuleAttrs);
1127 extModule.setPortSymbols(newArgSyms);
1129 extModule.setInternalPathsAttr(builder.getArrayAttr(newInternalPaths));
1134 bool TypeLoweringVisitor::visitDecl(FModuleOp module) {
1135 auto *body = module.getBodyBlock();
1137 ImplicitLocOpBuilder theBuilder(module.getLoc(), context);
1138 builder = &theBuilder;
1144 llvm::BitVector argsToRemove;
1145 auto newArgs = llvm::map_to_vector(module.getPorts(), [](
auto pi) {
1146 return PortInfoWithIP{pi, std::nullopt};
1148 for (
size_t argIndex = 0, argsRemoved = 0; argIndex < newArgs.size();
1150 SmallVector<Value> lowerings;
1151 if (lowerArg(module, argIndex, argsRemoved, newArgs, lowerings)) {
1152 auto arg = module.getArgument(argIndex);
1153 processUsers(arg, lowerings);
1154 argsToRemove.push_back(
true);
1157 argsToRemove.push_back(
false);
1162 body->eraseArguments(argsToRemove);
1163 for (
auto deadArg = argsToRemove.find_last(); deadArg != -1;
1164 deadArg = argsToRemove.find_prev(deadArg))
1165 newArgs.erase(newArgs.begin() + deadArg);
1167 SmallVector<NamedAttribute, 8> newModuleAttrs;
1170 for (
auto attr : module->getAttrDictionary())
1173 if (attr.getName() !=
"portNames" && attr.getName() !=
"portDirections" &&
1174 attr.getName() !=
"portTypes" && attr.getName() !=
"portAnnotations" &&
1175 attr.getName() !=
"portSyms" && attr.getName() !=
"portLocations")
1176 newModuleAttrs.push_back(attr);
1178 SmallVector<Direction> newArgDirections;
1179 SmallVector<Attribute> newArgNames;
1180 SmallVector<Attribute> newArgTypes;
1181 SmallVector<Attribute> newArgSyms;
1182 SmallVector<Attribute> newArgLocations;
1183 SmallVector<Attribute, 8> newArgAnnotations;
1184 for (
auto &port : newArgs) {
1185 newArgDirections.push_back(port.pi.direction);
1186 newArgNames.push_back(port.pi.name);
1188 newArgSyms.push_back(port.pi.sym);
1189 newArgLocations.push_back(port.pi.loc);
1190 newArgAnnotations.push_back(port.pi.annotations.getArrayAttr());
1193 newModuleAttrs.push_back(
1194 NamedAttribute(cache.sPortDirections,
1197 newModuleAttrs.push_back(
1198 NamedAttribute(cache.sPortNames, builder->getArrayAttr(newArgNames)));
1200 newModuleAttrs.push_back(
1201 NamedAttribute(cache.sPortTypes, builder->getArrayAttr(newArgTypes)));
1203 newModuleAttrs.push_back(NamedAttribute(
1204 cache.sPortLocations, builder->getArrayAttr(newArgLocations)));
1206 newModuleAttrs.push_back(NamedAttribute(
1207 cache.sPortAnnotations, builder->getArrayAttr(newArgAnnotations)));
1210 module->setAttrs(newModuleAttrs);
1211 module.setPortSymbols(newArgSyms);
1216 bool TypeLoweringVisitor::visitDecl(WireOp op) {
1217 if (op.isForceable())
1220 auto clone = [&](
const FlatBundleFieldEntry &field,
1221 ArrayAttr attrs) -> Value {
1223 ->create<WireOp>(
mapLoweredType(op.getDataRaw().getType(), field.type),
1224 "", NameKindEnum::DroppableName, attrs, StringAttr{})
1227 return lowerProducer(op, clone);
1231 bool TypeLoweringVisitor::visitDecl(RegOp op) {
1232 if (op.isForceable())
1235 auto clone = [&](
const FlatBundleFieldEntry &field,
1236 ArrayAttr attrs) -> Value {
1238 ->create<RegOp>(field.type, op.getClockVal(),
"",
1239 NameKindEnum::DroppableName, attrs, StringAttr{})
1242 return lowerProducer(op, clone);
1246 bool TypeLoweringVisitor::visitDecl(RegResetOp op) {
1247 if (op.isForceable())
1250 auto clone = [&](
const FlatBundleFieldEntry &field,
1251 ArrayAttr attrs) -> Value {
1252 auto resetVal = getSubWhatever(op.getResetValue(), field.index);
1254 ->create<RegResetOp>(field.type, op.getClockVal(), op.getResetSignal(),
1255 resetVal,
"", NameKindEnum::DroppableName, attrs,
1259 return lowerProducer(op, clone);
1263 bool TypeLoweringVisitor::visitDecl(NodeOp op) {
1264 if (op.isForceable())
1267 auto clone = [&](
const FlatBundleFieldEntry &field,
1268 ArrayAttr attrs) -> Value {
1269 auto input = getSubWhatever(op.getInput(), field.index);
1271 ->create<NodeOp>(input,
"", NameKindEnum::DroppableName, attrs)
1274 return lowerProducer(op, clone);
1278 bool TypeLoweringVisitor::visitExpr(InvalidValueOp op) {
1279 auto clone = [&](
const FlatBundleFieldEntry &field,
1280 ArrayAttr attrs) -> Value {
1281 return builder->create<InvalidValueOp>(field.type);
1283 return lowerProducer(op, clone);
1287 bool TypeLoweringVisitor::visitExpr(MuxPrimOp op) {
1288 auto clone = [&](
const FlatBundleFieldEntry &field,
1289 ArrayAttr attrs) -> Value {
1290 auto high = getSubWhatever(op.getHigh(), field.index);
1291 auto low = getSubWhatever(op.getLow(), field.index);
1292 return builder->create<MuxPrimOp>(op.getSel(), high, low);
1294 return lowerProducer(op, clone);
1298 bool TypeLoweringVisitor::visitExpr(Mux2CellIntrinsicOp op) {
1299 auto clone = [&](
const FlatBundleFieldEntry &field,
1300 ArrayAttr attrs) -> Value {
1301 auto high = getSubWhatever(op.getHigh(), field.index);
1302 auto low = getSubWhatever(op.getLow(), field.index);
1303 return builder->create<Mux2CellIntrinsicOp>(op.getSel(), high, low);
1305 return lowerProducer(op, clone);
1309 bool TypeLoweringVisitor::visitExpr(Mux4CellIntrinsicOp op) {
1310 auto clone = [&](
const FlatBundleFieldEntry &field,
1311 ArrayAttr attrs) -> Value {
1312 auto v3 = getSubWhatever(op.getV3(), field.index);
1313 auto v2 = getSubWhatever(op.getV2(), field.index);
1314 auto v1 = getSubWhatever(op.getV1(), field.index);
1315 auto v0 = getSubWhatever(op.getV0(), field.index);
1316 return builder->create<Mux4CellIntrinsicOp>(op.getSel(), v3, v2, v1, v0);
1318 return lowerProducer(op, clone);
1322 bool TypeLoweringVisitor::visitUnrealizedConversionCast(
1323 mlir::UnrealizedConversionCastOp op) {
1324 auto clone = [&](
const FlatBundleFieldEntry &field,
1325 ArrayAttr attrs) -> Value {
1326 auto input = getSubWhatever(op.getOperand(0), field.index);
1327 return builder->create<mlir::UnrealizedConversionCastOp>(field.type, input)
1332 if (!type_isa<FIRRTLType>(op->getOperand(0).getType()))
1334 return lowerProducer(op, clone);
1338 bool TypeLoweringVisitor::visitExpr(BitCastOp op) {
1339 Value srcLoweredVal = op.getInput();
1343 SmallVector<FlatBundleFieldEntry> fields;
1344 if (
peelType(op.getInput().getType(), fields, PreserveAggregate::None)) {
1345 size_t uptoBits = 0;
1348 for (
const auto &field : llvm::enumerate(fields)) {
1349 auto fieldBitwidth = *
getBitWidth(field.value().type);
1351 if (fieldBitwidth == 0)
1353 Value src = getSubWhatever(op.getInput(), field.index());
1355 src = builder->createOrFold<BitCastOp>(
1359 srcLoweredVal = src;
1361 srcLoweredVal = builder->create<CatPrimOp>(src, srcLoweredVal);
1363 uptoBits += fieldBitwidth;
1366 srcLoweredVal = builder->createOrFold<AsUIntPrimOp>(srcLoweredVal);
1370 if (type_isa<BundleType, FVectorType>(op.getResult().getType())) {
1372 size_t uptoBits = 0;
1373 auto clone = [&](
const FlatBundleFieldEntry &field,
1374 ArrayAttr attrs) -> Value {
1380 return builder->create<InvalidValueOp>(field.type);
1385 srcLoweredVal, uptoBits + fieldBits - 1, uptoBits);
1386 uptoBits += fieldBits;
1387 return builder->create<BitCastOp>(field.type,
extractBits);
1389 return lowerProducer(op, clone);
1393 if (type_isa<SIntType>(op.getType()))
1394 srcLoweredVal = builder->create<AsSIntPrimOp>(srcLoweredVal);
1395 op.getResult().replaceAllUsesWith(srcLoweredVal);
1399 bool TypeLoweringVisitor::visitExpr(RefSendOp op) {
1400 auto clone = [&](
const FlatBundleFieldEntry &field,
1401 ArrayAttr attrs) -> Value {
1402 return builder->create<RefSendOp>(
1403 getSubWhatever(op.getBase(), field.index));
1408 return lowerProducer(op, clone);
1411 bool TypeLoweringVisitor::visitExpr(RefResolveOp op) {
1412 auto clone = [&](
const FlatBundleFieldEntry &field,
1413 ArrayAttr attrs) -> Value {
1414 Value src = getSubWhatever(op.getRef(), field.index);
1415 return builder->create<RefResolveOp>(src);
1419 return lowerProducer(op, clone, op.getRef().getType());
1422 bool TypeLoweringVisitor::visitExpr(RefCastOp op) {
1423 auto clone = [&](
const FlatBundleFieldEntry &field,
1424 ArrayAttr attrs) -> Value {
1425 auto input = getSubWhatever(op.getInput(), field.index);
1426 return builder->create<RefCastOp>(
RefType::get(field.type,
1427 op.getType().getForceable(),
1428 op.getType().getLayer()),
1431 return lowerProducer(op, clone);
1434 bool TypeLoweringVisitor::visitDecl(InstanceOp op) {
1436 SmallVector<Type, 8> resultTypes;
1437 SmallVector<int64_t, 8> endFields;
1438 auto oldPortAnno = op.getPortAnnotations();
1439 SmallVector<Direction> newDirs;
1440 SmallVector<Attribute> newNames;
1441 SmallVector<Attribute> newPortAnno;
1443 cast<FModuleLike>(op.getReferencedOperation(symTbl)));
1445 endFields.push_back(0);
1446 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
1447 auto srcType = type_cast<FIRRTLType>(op.getType(i));
1450 SmallVector<FlatBundleFieldEntry, 8> fieldTypes;
1451 if (!
peelType(srcType, fieldTypes, mode)) {
1452 newDirs.push_back(op.getPortDirection(i));
1453 newNames.push_back(op.getPortName(i));
1454 resultTypes.push_back(srcType);
1455 newPortAnno.push_back(oldPortAnno[i]);
1458 auto oldName = op.getPortNameStr(i);
1459 auto oldDir = op.getPortDirection(i);
1461 for (
const auto &field : fieldTypes) {
1462 newDirs.push_back(
direction::get((
unsigned)oldDir ^ field.isOutput));
1463 newNames.push_back(builder->getStringAttr(oldName + field.suffix));
1465 auto annos = filterAnnotations(
1466 context, dyn_cast_or_null<ArrayAttr>(oldPortAnno[i]), srcType,
1468 newPortAnno.push_back(annos);
1471 endFields.push_back(resultTypes.size());
1481 auto newInstance = builder->create<InstanceOp>(
1482 resultTypes, op.getModuleNameAttr(), op.getNameAttr(),
1484 builder->getArrayAttr(newNames), op.getAnnotations(),
1485 builder->getArrayAttr(newPortAnno), op.getLayersAttr(),
1486 op.getLowerToBindAttr(),
1491 auto attrNames = InstanceOp::getAttributeNames();
1492 DenseSet<StringRef> attrSet(attrNames.begin(), attrNames.end());
1493 SmallVector<NamedAttribute> newAttrs(newInstance->getAttrs());
1494 for (
auto i : llvm::make_filter_range(op->getAttrs(), [&](
auto namedAttr) {
1495 return !attrSet.count(namedAttr.getName());
1497 newAttrs.push_back(i);
1498 newInstance->setAttrs(newAttrs);
1500 SmallVector<Value> lowered;
1501 for (
size_t aggIndex = 0, eAgg = op.getNumResults(); aggIndex != eAgg;
1504 for (
size_t fieldIndex = endFields[aggIndex],
1505 eField = endFields[aggIndex + 1];
1506 fieldIndex < eField; ++fieldIndex)
1507 lowered.push_back(newInstance.getResult(fieldIndex));
1508 if (lowered.size() != 1 ||
1509 op.getType(aggIndex) != resultTypes[endFields[aggIndex]])
1510 processUsers(op.getResult(aggIndex), lowered);
1512 op.getResult(aggIndex).replaceAllUsesWith(lowered[0]);
1517 bool TypeLoweringVisitor::visitExpr(SubaccessOp op) {
1518 auto input = op.getInput();
1519 FVectorType vType = input.getType();
1522 if (vType.getNumElements() == 0) {
1523 Value inv = builder->create<InvalidValueOp>(vType.getElementType());
1524 op.replaceAllUsesWith(inv);
1529 if (ConstantOp arg =
1530 llvm::dyn_cast_or_null<ConstantOp>(op.getIndex().getDefiningOp())) {
1531 auto sio = builder->create<SubindexOp>(op.getInput(),
1532 arg.getValue().getExtValue());
1533 op.replaceAllUsesWith(sio.getResult());
1538 SmallVector<Value> inputs;
1539 inputs.reserve(vType.getNumElements());
1540 for (
int index = vType.getNumElements() - 1; index >= 0; index--)
1541 inputs.push_back(builder->create<SubindexOp>(input, index));
1543 Value multibitMux = builder->create<MultibitMuxOp>(op.getIndex(), inputs);
1544 op.replaceAllUsesWith(multibitMux);
1548 bool TypeLoweringVisitor::visitExpr(VectorCreateOp op) {
1549 auto clone = [&](
const FlatBundleFieldEntry &field,
1550 ArrayAttr attrs) -> Value {
1551 return op.getOperand(field.index);
1553 return lowerProducer(op, clone);
1556 bool TypeLoweringVisitor::visitExpr(BundleCreateOp op) {
1557 auto clone = [&](
const FlatBundleFieldEntry &field,
1558 ArrayAttr attrs) -> Value {
1559 return op.getOperand(field.index);
1561 return lowerProducer(op, clone);
1564 bool TypeLoweringVisitor::visitExpr(ElementwiseOrPrimOp op) {
1565 auto clone = [&](
const FlatBundleFieldEntry &field,
1566 ArrayAttr attrs) -> Value {
1567 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1568 getSubWhatever(op.getRhs(), field.index)};
1569 return type_isa<BundleType, FVectorType>(field.type)
1570 ? (Value)builder->create<ElementwiseOrPrimOp>(field.type,
1572 : (Value)builder->create<OrPrimOp>(operands);
1575 return lowerProducer(op, clone);
1578 bool TypeLoweringVisitor::visitExpr(ElementwiseAndPrimOp op) {
1579 auto clone = [&](
const FlatBundleFieldEntry &field,
1580 ArrayAttr attrs) -> Value {
1581 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1582 getSubWhatever(op.getRhs(), field.index)};
1583 return type_isa<BundleType, FVectorType>(field.type)
1584 ? (Value)builder->create<ElementwiseAndPrimOp>(field.type,
1586 : (Value)builder->create<AndPrimOp>(operands);
1589 return lowerProducer(op, clone);
1592 bool TypeLoweringVisitor::visitExpr(ElementwiseXorPrimOp op) {
1593 auto clone = [&](
const FlatBundleFieldEntry &field,
1594 ArrayAttr attrs) -> Value {
1595 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1596 getSubWhatever(op.getRhs(), field.index)};
1597 return type_isa<BundleType, FVectorType>(field.type)
1598 ? (Value)builder->create<ElementwiseXorPrimOp>(field.type,
1600 : (Value)builder->create<XorPrimOp>(operands);
1603 return lowerProducer(op, clone);
1606 bool TypeLoweringVisitor::visitExpr(MultibitMuxOp op) {
1607 auto clone = [&](
const FlatBundleFieldEntry &field,
1608 ArrayAttr attrs) -> Value {
1609 SmallVector<Value> newInputs;
1610 newInputs.reserve(op.getInputs().size());
1611 for (
auto input : op.getInputs()) {
1612 auto inputSub = getSubWhatever(input, field.index);
1613 newInputs.push_back(inputSub);
1615 return builder->create<MultibitMuxOp>(op.getIndex(), newInputs);
1617 return lowerProducer(op, clone);
1625 struct LowerTypesPass
1626 :
public circt::firrtl::impl::LowerFIRRTLTypesBase<LowerTypesPass> {
1630 preserveAggregate = preserveAggregateFlag;
1631 preserveMemories = preserveMemoriesFlag;
1633 void runOnOperation()
override;
1638 void LowerTypesPass::runOnOperation() {
1640 std::vector<FModuleLike> ops;
1642 auto &symTbl = getAnalysis<SymbolTable>();
1644 AttrCache cache(&getContext());
1646 DenseMap<FModuleLike, Convention> conventionTable;
1647 auto circuit = getOperation();
1648 for (
auto module : circuit.getOps<FModuleLike>()) {
1649 conventionTable.insert({module, module.getConvention()});
1650 ops.push_back(module);
1654 auto lowerModules = [&](FModuleLike op) -> LogicalResult {
1656 TypeLoweringVisitor(&getContext(), preserveAggregate, preserveMemories,
1657 symTbl, cache, conventionTable);
1660 return LogicalResult::failure(tl.isFailed());
1663 auto result = failableParallelForEach(&getContext(), ops, lowerModules);
1666 signalPassFailure();
1673 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.
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.