39 #include "mlir/IR/ImplicitLocOpBuilder.h"
40 #include "mlir/IR/Threading.h"
41 #include "mlir/Pass/Pass.h"
42 #include "llvm/ADT/APSInt.h"
43 #include "llvm/ADT/BitVector.h"
44 #include "llvm/Support/Debug.h"
46 #define DEBUG_TYPE "firrtl-lower-types"
50 #define GEN_PASS_DEF_LOWERFIRRTLTYPES
51 #include "circt/Dialect/FIRRTL/Passes.h.inc"
55 using namespace circt;
56 using namespace firrtl;
61 struct FlatBundleFieldEntry {
69 SmallString<16> suffix;
74 unsigned fieldID, StringRef suffix,
bool isOutput)
75 : type(type), index(index), fieldID(fieldID), suffix(suffix),
79 llvm::errs() <<
"FBFE{" << type <<
" index<" << index <<
"> fieldID<"
80 << fieldID <<
"> suffix<" << suffix <<
"> isOutput<"
81 << isOutput <<
">}\n";
86 struct PortInfoWithIP {
88 std::optional<InternalPathAttr> internalPath;
95 return mapBaseType(type, [&](
auto) {
return fieldType; });
100 auto ftype = type_dyn_cast<FIRRTLType>(type);
109 .
Case<BundleType>([&](
auto bundle) {
return false; })
110 .Case<FVectorType>([&](FVectorType vector) {
112 return vector.getElementType().isGround() &&
113 vector.getNumElements() > 1;
115 .Default([](
auto groundType) {
return true; });
122 .
Case<BundleType>([&](
auto bundle) {
return true; })
123 .Case<FVectorType>([&](FVectorType vector) {
126 .Default([](
auto groundType) {
return false; });
133 if (
auto refType = type_dyn_cast<RefType>(type)) {
135 if (refType.getForceable())
146 auto firrtlType = type_dyn_cast<FIRRTLBaseType>(type);
152 if (!firrtlType.isPassive() || firrtlType.containsAnalog() ||
164 llvm_unreachable(
"unexpected mode");
170 static bool peelType(Type type, SmallVectorImpl<FlatBundleFieldEntry> &fields,
177 if (
auto refType = type_dyn_cast<RefType>(type))
178 type = refType.getType();
180 .
Case<BundleType>([&](
auto bundle) {
181 SmallString<16> tmpSuffix;
183 for (
size_t i = 0, e = bundle.getNumElements(); i < e; ++i) {
184 auto elt = bundle.getElement(i);
187 tmpSuffix.push_back(
'_');
188 tmpSuffix.append(elt.name.getValue());
189 fields.emplace_back(elt.type, i, bundle.getFieldID(i), tmpSuffix,
194 .Case<FVectorType>([&](
auto vector) {
196 for (
size_t i = 0, e = vector.getNumElements(); i != e; ++i) {
197 fields.emplace_back(vector.getElementType(), i, vector.getFieldID(i),
198 "_" + std::to_string(i),
false);
202 .Default([](
auto op) {
return false; });
208 SubaccessOp sao = llvm::dyn_cast<SubaccessOp>(op);
212 llvm::dyn_cast_or_null<ConstantOp>(sao.getIndex().getDefiningOp());
213 return arg && sao.getInput().getType().base().getNumElements() != 0;
218 SmallVector<Operation *> retval;
219 auto defOp = op->getOperand(0).getDefiningOp();
220 while (isa_and_nonnull<SubfieldOp, SubindexOp, SubaccessOp>(defOp)) {
221 retval.push_back(defOp);
222 defOp = defOp->getOperand(0).getDefiningOp();
232 FlatBundleFieldEntry field) {
233 SmallVector<Type, 8> ports;
234 SmallVector<Attribute, 8> portNames;
235 SmallVector<Attribute, 8> portLocations;
237 auto oldPorts = op.getPorts();
238 for (
size_t portIdx = 0, e = oldPorts.size(); portIdx < e; ++portIdx) {
239 auto port = oldPorts[portIdx];
241 MemOp::getTypeForPort(op.getDepth(), field.type, port.second));
242 portNames.push_back(port.first);
246 auto newMem = b->create<MemOp>(
247 ports, op.getReadLatency(), op.getWriteLatency(), op.getDepth(),
248 op.getRuw(), b->getArrayAttr(portNames),
249 (op.getName() + field.suffix).str(), op.getNameKind(),
250 op.getAnnotations(), op.getPortAnnotations(), op.getInnerSymAttr(),
251 op.getInitAttr(), op.getPrefixAttr());
253 if (op.getInnerSym()) {
254 op.emitError(
"cannot split memory with symbol present");
258 SmallVector<Attribute> newAnnotations;
259 for (
size_t portIdx = 0, e = newMem.getNumResults(); portIdx < e; ++portIdx) {
260 auto portType = type_cast<BundleType>(newMem.getResult(portIdx).getType());
261 auto oldPortType = type_cast<BundleType>(op.getResult(portIdx).getType());
262 SmallVector<Attribute> portAnno;
263 for (
auto attr : newMem.getPortAnnotation(portIdx)) {
266 auto targetIndex = oldPortType.getIndexForFieldID(annoFieldID);
270 if (annoFieldID == oldPortType.getFieldID(targetIndex)) {
273 b->getI32IntegerAttr(portType.getFieldID(targetIndex)));
274 portAnno.push_back(anno.
getDict());
279 if (type_isa<BundleType>(oldPortType.getElement(targetIndex).type)) {
284 auto fieldID = field.fieldID + oldPortType.getFieldID(targetIndex);
285 if (annoFieldID >= fieldID &&
290 annoFieldID - fieldID + portType.getFieldID(targetIndex);
291 anno.
setMember(
"circt.fieldID", b->getI32IntegerAttr(newFieldID));
292 portAnno.push_back(anno.
getDict());
296 portAnno.push_back(attr);
298 newAnnotations.push_back(b->getArrayAttr(portAnno));
300 newMem.setAllPortAnnotations(newAnnotations);
310 AttrCache(MLIRContext *context) {
322 AttrCache(
const AttrCache &) =
default;
325 StringAttr nameAttr, nameKindAttr, sPortDirections, sPortNames, sPortTypes,
326 sPortSymbols, sPortLocations, sPortAnnotations, sEmpty;
331 struct TypeLoweringVisitor :
public FIRRTLVisitor<TypeLoweringVisitor, bool> {
335 Convention bodyConvention,
337 SymbolTable &symTbl,
const AttrCache &cache,
338 const llvm::DenseMap<FModuleLike, Convention> &conventionTable)
339 : context(context), defaultAggregatePreservationMode(preserveAggregate),
340 memoryPreservationMode(memoryPreservationMode), symTbl(symTbl),
341 cache(cache), conventionTable(conventionTable) {
342 bodyAggregatePreservationMode = bodyConvention == Convention::Scalarized
344 : defaultAggregatePreservationMode;
352 void lowerModule(FModuleLike op);
354 bool lowerArg(FModuleLike module,
size_t argIndex,
size_t argsRemoved,
355 SmallVectorImpl<PortInfoWithIP> &newArgs,
356 SmallVectorImpl<Value> &lowering);
357 std::pair<Value, PortInfoWithIP>
358 addArg(Operation *module,
unsigned insertPt,
unsigned insertPtOffset,
359 FIRRTLType srcType,
const FlatBundleFieldEntry &field,
360 PortInfoWithIP &oldArg, hw::InnerSymAttr newSym);
363 bool visitDecl(FExtModuleOp op);
364 bool visitDecl(FModuleOp op);
365 bool visitDecl(InstanceOp op);
366 bool visitDecl(MemOp op);
367 bool visitDecl(NodeOp op);
368 bool visitDecl(RegOp op);
369 bool visitDecl(WireOp op);
370 bool visitDecl(RegResetOp op);
371 bool visitExpr(InvalidValueOp op);
372 bool visitExpr(SubaccessOp op);
373 bool visitExpr(VectorCreateOp op);
374 bool visitExpr(BundleCreateOp op);
375 bool visitExpr(ElementwiseAndPrimOp op);
376 bool visitExpr(ElementwiseOrPrimOp op);
377 bool visitExpr(ElementwiseXorPrimOp op);
378 bool visitExpr(MultibitMuxOp op);
379 bool visitExpr(MuxPrimOp op);
380 bool visitExpr(Mux2CellIntrinsicOp op);
381 bool visitExpr(Mux4CellIntrinsicOp op);
382 bool visitExpr(BitCastOp op);
383 bool visitExpr(RefSendOp op);
384 bool visitExpr(RefResolveOp op);
385 bool visitExpr(RefCastOp op);
386 bool visitStmt(ConnectOp op);
387 bool visitStmt(MatchingConnectOp op);
388 bool visitStmt(RefDefineOp op);
389 bool visitStmt(WhenOp op);
390 bool visitStmt(LayerBlockOp op);
391 bool visitUnrealizedConversionCast(mlir::UnrealizedConversionCastOp op);
393 bool isFailed()
const {
return encounteredError; }
395 bool visitInvalidOp(Operation *op) {
396 if (
auto castOp = dyn_cast<mlir::UnrealizedConversionCastOp>(op))
397 return visitUnrealizedConversionCast(castOp);
402 void processUsers(Value val, ArrayRef<Value> mapping);
403 bool processSAPath(Operation *);
404 void lowerBlock(Block *);
405 void lowerSAWritePath(Operation *, ArrayRef<Operation *> writePath);
415 llvm::function_ref<Value(
const FlatBundleFieldEntry &, ArrayAttr)> clone,
420 ArrayAttr filterAnnotations(MLIRContext *
ctxt, ArrayAttr annotations,
421 FIRRTLType srcType, FlatBundleFieldEntry field);
425 LogicalResult partitionSymbols(hw::InnerSymAttr sym,
FIRRTLType parentType,
426 SmallVectorImpl<hw::InnerSymAttr> &newSyms,
430 getPreservationModeForPorts(FModuleLike moduleLike);
431 Value getSubWhatever(Value val,
size_t index);
433 size_t uniqueIdx = 0;
434 std::string uniqueName() {
435 auto myID = uniqueIdx++;
436 return (Twine(
"__GEN_") + Twine(myID)).str();
439 MLIRContext *context;
447 ImplicitLocOpBuilder *builder;
453 const AttrCache &cache;
455 const llvm::DenseMap<FModuleLike, Convention> &conventionTable;
458 bool encounteredError =
false;
465 TypeLoweringVisitor::getPreservationModeForPorts(FModuleLike module) {
466 auto lookup = conventionTable.find(module);
467 if (lookup == conventionTable.end())
468 return defaultAggregatePreservationMode;
469 switch (lookup->second) {
470 case Convention::Scalarized:
472 case Convention::Internal:
473 return defaultAggregatePreservationMode;
475 llvm_unreachable(
"Unknown convention");
476 return defaultAggregatePreservationMode;
479 Value TypeLoweringVisitor::getSubWhatever(Value val,
size_t index) {
480 if (type_isa<BundleType>(val.getType()))
481 return builder->create<SubfieldOp>(val, index);
482 if (type_isa<FVectorType>(val.getType()))
483 return builder->create<SubindexOp>(val, index);
484 if (type_isa<RefType>(val.getType()))
485 return builder->create<RefSubOp>(val, index);
486 llvm_unreachable(
"Unknown aggregate type");
491 bool TypeLoweringVisitor::processSAPath(Operation *op) {
494 if (writePath.empty())
497 lowerSAWritePath(op, writePath);
500 op->eraseOperands(0, 2);
502 for (
size_t i = 0; i < writePath.size(); ++i) {
503 if (writePath[i]->use_empty()) {
504 writePath[i]->erase();
512 void TypeLoweringVisitor::lowerBlock(Block *block) {
514 for (
auto it = block->rbegin(), e = block->rend(); it != e;) {
516 builder->setInsertionPoint(&iop);
517 builder->setLoc(iop.getLoc());
518 bool removeOp = dispatchVisitor(&iop);
527 ArrayAttr TypeLoweringVisitor::filterAnnotations(MLIRContext *
ctxt,
528 ArrayAttr annotations,
530 FlatBundleFieldEntry field) {
531 SmallVector<Attribute> retval;
532 if (!annotations || annotations.empty())
534 for (
auto opAttr : annotations) {
536 auto fieldID = anno.getFieldID();
537 anno.removeMember(
"circt.fieldID");
542 retval.push_back(anno.getAttr());
547 if (fieldID < field.fieldID ||
552 if (
auto newFieldID = fieldID - field.fieldID) {
555 anno.setMember(
"circt.fieldID", builder->getI32IntegerAttr(newFieldID));
558 retval.push_back(anno.getAttr());
563 LogicalResult TypeLoweringVisitor::partitionSymbols(
565 SmallVectorImpl<hw::InnerSymAttr> &newSyms, Location errorLoc) {
568 if (!sym || sym.empty())
571 auto *context = sym.getContext();
575 return mlir::emitError(errorLoc,
576 "unable to partition symbol on unsupported type ")
579 return TypeSwitch<FIRRTLType, LogicalResult>(baseType)
580 .Case<BundleType, FVectorType>([&](
auto aggType) -> LogicalResult {
584 hw::InnerSymPropertiesAttr prop;
588 SmallVector<BinningInfo> binning;
589 for (
auto prop : sym) {
590 auto fieldID = prop.getFieldID();
593 return mlir::emitError(errorLoc,
"unable to lower due to symbol ")
595 <<
" with target not preserved by lowering";
596 auto [index, relFieldID] = aggType.getIndexAndSubfieldID(fieldID);
597 binning.push_back({index, relFieldID, prop});
601 llvm::stable_sort(binning, [&](
auto &lhs,
auto &rhs) {
602 return std::tuple(lhs.index, lhs.relFieldID) <
603 std::tuple(rhs.index, rhs.relFieldID);
608 newSyms.resize(aggType.getNumElements());
609 for (
auto binIt = binning.begin(), binEnd = binning.end();
611 auto curIndex = binIt->index;
612 SmallVector<hw::InnerSymPropertiesAttr> propsForIndex;
614 while (binIt != binEnd && binIt->index == curIndex) {
616 context, binIt->prop.getName(), binIt->relFieldID,
617 binIt->prop.getSymVisibility()));
621 assert(!newSyms[curIndex]);
626 .Default([&](
auto ty) {
627 return mlir::emitError(
628 errorLoc,
"unable to partition symbol on unsupported type ")
633 bool TypeLoweringVisitor::lowerProducer(
635 llvm::function_ref<Value(
const FlatBundleFieldEntry &, ArrayAttr)> clone,
639 srcType = op->getResult(0).getType();
640 auto srcFType = type_dyn_cast<FIRRTLType>(srcType);
643 SmallVector<FlatBundleFieldEntry, 8> fieldTypes;
645 if (!
peelType(srcFType, fieldTypes, bodyAggregatePreservationMode))
648 SmallVector<Value> lowered;
650 SmallString<16> loweredName;
651 auto nameKindAttr = op->getAttrOfType<NameKindEnumAttr>(cache.nameKindAttr);
653 if (
auto nameAttr = op->getAttrOfType<StringAttr>(cache.nameAttr))
654 loweredName = nameAttr.getValue();
655 auto baseNameLen = loweredName.size();
656 auto oldAnno = dyn_cast_or_null<ArrayAttr>(op->getAttr(
"annotations"));
658 SmallVector<hw::InnerSymAttr> fieldSyms(fieldTypes.size());
659 if (
auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(op)) {
660 if (failed(partitionSymbols(symOp.getInnerSymAttr(), srcFType, fieldSyms,
662 encounteredError =
true;
667 for (
const auto &[field, sym] : llvm::zip_equal(fieldTypes, fieldSyms)) {
668 if (!loweredName.empty()) {
669 loweredName.resize(baseNameLen);
670 loweredName += field.suffix;
675 ArrayAttr loweredAttrs =
676 filterAnnotations(context, oldAnno, srcFType, field);
677 auto newVal = clone(field, loweredAttrs);
683 auto newSymOp = newVal.getDefiningOp<hw::InnerSymbolOpInterface>();
686 "op with inner symbol lowered to op that cannot take inner symbol");
687 newSymOp.setInnerSymbolAttr(sym);
691 if (
auto *newOp = newVal.getDefiningOp()) {
692 if (!loweredName.empty())
695 newOp->setAttr(cache.nameKindAttr, nameKindAttr);
698 newOp->setDiscardableAttrs(op->getDiscardableAttrDictionary());
700 lowered.push_back(newVal);
703 processUsers(op->getResult(0), lowered);
707 void TypeLoweringVisitor::processUsers(Value val, ArrayRef<Value> mapping) {
708 for (
auto *user : llvm::make_early_inc_range(val.getUsers())) {
709 TypeSwitch<Operation *, void>(user)
710 .Case<SubindexOp>([mapping](SubindexOp sio) {
711 Value repl = mapping[sio.getIndex()];
712 sio.replaceAllUsesWith(repl);
715 .Case<SubfieldOp>([mapping](SubfieldOp sfo) {
717 Value repl = mapping[sfo.getFieldIndex()];
718 sfo.replaceAllUsesWith(repl);
721 .Case<RefSubOp>([mapping](RefSubOp refSub) {
722 Value repl = mapping[refSub.getIndex()];
723 refSub.replaceAllUsesWith(repl);
726 .Default([&](
auto op) {
737 ImplicitLocOpBuilder b(user->getLoc(), user);
741 assert(llvm::none_of(mapping, [](
auto v) {
742 auto fbasetype = type_dyn_cast<FIRRTLBaseType>(v.getType());
743 return !fbasetype || fbasetype.containsReference();
747 TypeSwitch<Type, Value>(val.getType())
748 .template Case<FVectorType>([&](
auto vecType) {
749 return b.createOrFold<VectorCreateOp>(vecType, mapping);
751 .
template Case<BundleType>([&](
auto bundleType) {
752 return b.createOrFold<BundleCreateOp>(bundleType, mapping);
754 .Default([&](
auto _) -> Value {
return {}; });
756 user->emitError(
"unable to reconstruct source of type ")
758 encounteredError =
true;
761 user->replaceUsesOfWith(val, input);
766 void TypeLoweringVisitor::lowerModule(FModuleLike op) {
767 if (
auto module = llvm::dyn_cast<FModuleOp>(*op))
769 else if (
auto extModule = llvm::dyn_cast<FExtModuleOp>(*op))
770 visitDecl(extModule);
776 std::pair<Value, PortInfoWithIP>
777 TypeLoweringVisitor::addArg(Operation *module,
unsigned insertPt,
779 const FlatBundleFieldEntry &field,
780 PortInfoWithIP &oldArg, hw::InnerSymAttr newSym) {
783 if (
auto mod = llvm::dyn_cast<FModuleOp>(module)) {
784 Block *body = mod.getBodyBlock();
786 newValue = body->insertArgument(insertPt, fieldType, oldArg.pi.loc);
790 auto name = builder->getStringAttr(oldArg.pi.name.getValue() + field.suffix);
793 auto newAnnotations = filterAnnotations(
794 context, oldArg.pi.annotations.getArrayAttr(), srcType, field);
796 auto direction = (
Direction)((
unsigned)oldArg.pi.direction ^ field.isOutput);
798 return std::make_pair(
800 PortInfoWithIP{
PortInfo{name, fieldType, direction, newSym, oldArg.pi.loc,
802 oldArg.internalPath});
806 bool TypeLoweringVisitor::lowerArg(FModuleLike module,
size_t argIndex,
808 SmallVectorImpl<PortInfoWithIP> &newArgs,
809 SmallVectorImpl<Value> &lowering) {
812 SmallVector<FlatBundleFieldEntry> fieldTypes;
813 auto srcType = type_cast<FIRRTLType>(newArgs[argIndex].pi.type);
814 if (!
peelType(srcType, fieldTypes, getPreservationModeForPorts(module)))
818 if (
auto ip = newArgs[argIndex].internalPath; ip && ip->getPath()) {
819 ::mlir::emitError(newArgs[argIndex].pi.loc,
820 "cannot lower port with internal path");
821 encounteredError =
true;
825 SmallVector<hw::InnerSymAttr> fieldSyms(fieldTypes.size());
826 if (failed(partitionSymbols(newArgs[argIndex].pi.sym, srcType, fieldSyms,
827 newArgs[argIndex].pi.loc))) {
828 encounteredError =
true;
832 for (
const auto &[idx, field, fieldSym] :
833 llvm::enumerate(fieldTypes, fieldSyms)) {
834 auto newValue = addArg(module, 1 + argIndex + idx, argsRemoved, srcType,
835 field, newArgs[argIndex], fieldSym);
836 newArgs.insert(newArgs.begin() + 1 + argIndex + idx, newValue.second);
838 lowering.push_back(newValue.first);
843 static Value
cloneAccess(ImplicitLocOpBuilder *builder, Operation *op,
845 if (
auto rop = llvm::dyn_cast<SubfieldOp>(op))
846 return builder->create<SubfieldOp>(rhs, rop.getFieldIndex());
847 if (
auto rop = llvm::dyn_cast<SubindexOp>(op))
848 return builder->create<SubindexOp>(rhs, rop.getIndex());
849 if (
auto rop = llvm::dyn_cast<SubaccessOp>(op))
850 return builder->create<SubaccessOp>(rhs, rop.getIndex());
851 op->emitError(
"Unknown accessor");
855 void TypeLoweringVisitor::lowerSAWritePath(Operation *op,
856 ArrayRef<Operation *> writePath) {
857 SubaccessOp sao = cast<SubaccessOp>(writePath.back());
858 FVectorType saoType = sao.getInput().getType();
859 auto selectWidth = llvm::Log2_64_Ceil(saoType.getNumElements());
861 for (
size_t index = 0, e = saoType.getNumElements(); index < e; ++index) {
862 auto cond = builder->create<EQPrimOp>(
864 builder->createOrFold<ConstantOp>(
UIntType::get(context, selectWidth),
865 APInt(selectWidth, index)));
866 builder->create<WhenOp>(cond,
false, [&]() {
868 Value leaf = builder->create<SubindexOp>(sao.getInput(), index);
869 for (
int i = writePath.size() - 2; i >= 0; --i) {
870 if (
auto access =
cloneAccess(builder, writePath[i], leaf))
873 encounteredError =
true;
884 bool TypeLoweringVisitor::visitStmt(ConnectOp op) {
885 if (processSAPath(op))
889 SmallVector<FlatBundleFieldEntry> fields;
896 for (
const auto &field : llvm::enumerate(fields)) {
897 Value src = getSubWhatever(op.getSrc(), field.index());
898 Value dest = getSubWhatever(op.getDest(), field.index());
899 if (field.value().isOutput)
900 std::swap(src, dest);
907 bool TypeLoweringVisitor::visitStmt(MatchingConnectOp op) {
908 if (processSAPath(op))
912 SmallVector<FlatBundleFieldEntry> fields;
919 for (
const auto &field : llvm::enumerate(fields)) {
920 Value src = getSubWhatever(op.getSrc(), field.index());
921 Value dest = getSubWhatever(op.getDest(), field.index());
922 if (field.value().isOutput)
923 std::swap(src, dest);
924 builder->create<MatchingConnectOp>(dest, src);
930 bool TypeLoweringVisitor::visitStmt(RefDefineOp op) {
932 SmallVector<FlatBundleFieldEntry> fields;
934 if (!
peelType(op.getDest().getType(), fields, bodyAggregatePreservationMode))
938 for (
const auto &field : llvm::enumerate(fields)) {
939 Value src = getSubWhatever(op.getSrc(), field.index());
940 Value dest = getSubWhatever(op.getDest(), field.index());
941 assert(!field.value().isOutput &&
"unexpected flip in reftype destination");
942 builder->create<RefDefineOp>(dest, src);
947 bool TypeLoweringVisitor::visitStmt(WhenOp op) {
953 lowerBlock(&op.getThenBlock());
956 if (op.hasElseRegion())
957 lowerBlock(&op.getElseBlock());
962 bool TypeLoweringVisitor::visitStmt(LayerBlockOp op) {
963 lowerBlock(op.getBody());
969 bool TypeLoweringVisitor::visitDecl(MemOp op) {
971 SmallVector<FlatBundleFieldEntry> fields;
974 if (!
peelType(op.getDataType(), fields, memoryPreservationMode))
977 if (op.getInnerSym()) {
978 op->emitError() <<
"has a symbol, but no symbols may exist on aggregates "
979 "passed through LowerTypes";
980 encounteredError =
true;
984 SmallVector<MemOp> newMemories;
985 SmallVector<WireOp> oldPorts;
988 for (
unsigned int index = 0, end = op.getNumResults(); index < end; ++index) {
989 auto result = op.getResult(index);
990 if (op.getPortKind(index) == MemOp::PortKind::Debug) {
991 op.emitOpError(
"cannot lower memory with debug port");
992 encounteredError =
true;
995 auto wire = builder->create<WireOp>(
997 (op.getName() +
"_" + op.getPortName(index).getValue()).str());
998 oldPorts.push_back(wire);
999 result.replaceAllUsesWith(wire.getResult());
1006 for (
const auto &field : fields) {
1008 if (!newMemForField) {
1009 op.emitError(
"failed cloning memory for field");
1010 encounteredError =
true;
1013 newMemories.push_back(newMemForField);
1016 for (
size_t index = 0, rend = op.getNumResults(); index < rend; ++index) {
1017 auto result = oldPorts[index].getResult();
1018 auto rType = type_cast<BundleType>(result.getType());
1019 for (
size_t fieldIndex = 0, fend = rType.getNumElements();
1020 fieldIndex != fend; ++fieldIndex) {
1021 auto name = rType.getElement(fieldIndex).name.getValue();
1022 auto oldField = builder->create<SubfieldOp>(result, fieldIndex);
1025 if (name ==
"data" || name ==
"mask" || name ==
"wdata" ||
1026 name ==
"wmask" || name ==
"rdata") {
1027 for (
const auto &field : fields) {
1028 auto realOldField = getSubWhatever(oldField, field.index);
1029 auto newField = getSubWhatever(
1030 newMemories[field.index].getResult(index), fieldIndex);
1031 if (rType.getElement(fieldIndex).isFlip)
1032 std::swap(realOldField, newField);
1036 for (
auto mem : newMemories) {
1038 builder->create<SubfieldOp>(mem.getResult(index), fieldIndex);
1047 bool TypeLoweringVisitor::visitDecl(FExtModuleOp extModule) {
1048 ImplicitLocOpBuilder theBuilder(extModule.getLoc(), context);
1049 builder = &theBuilder;
1052 OpBuilder builder(context);
1054 auto internalPaths = extModule.getInternalPaths();
1057 SmallVector<unsigned> argsToRemove;
1058 SmallVector<PortInfoWithIP> newArgs;
1059 for (
auto [idx, pi] : llvm::enumerate(extModule.getPorts())) {
1060 std::optional<InternalPathAttr> internalPath;
1062 internalPath = cast<InternalPathAttr>(internalPaths->getValue()[idx]);
1063 newArgs.push_back({pi, internalPath});
1066 for (
size_t argIndex = 0, argsRemoved = 0; argIndex < newArgs.size();
1068 SmallVector<Value> lowering;
1069 if (lowerArg(extModule, argIndex, argsRemoved, newArgs, lowering)) {
1070 argsToRemove.push_back(argIndex);
1077 for (
auto toRemove : llvm::reverse(argsToRemove))
1078 newArgs.erase(newArgs.begin() + toRemove);
1080 SmallVector<NamedAttribute, 8> newModuleAttrs;
1083 for (
auto attr : extModule->getAttrDictionary())
1086 if (attr.getName() !=
"portDirections" && attr.getName() !=
"portNames" &&
1087 attr.getName() !=
"portTypes" && attr.getName() !=
"portAnnotations" &&
1088 attr.getName() !=
"portSymbols" && attr.getName() !=
"portLocations")
1089 newModuleAttrs.push_back(attr);
1091 SmallVector<Direction> newArgDirections;
1092 SmallVector<Attribute> newArgNames;
1093 SmallVector<Attribute, 8> newArgTypes;
1094 SmallVector<Attribute, 8> newArgSyms;
1095 SmallVector<Attribute, 8> newArgLocations;
1096 SmallVector<Attribute, 8> newArgAnnotations;
1097 SmallVector<Attribute, 8> newInternalPaths;
1100 for (
auto &port : newArgs) {
1101 newArgDirections.push_back(port.pi.direction);
1102 newArgNames.push_back(port.pi.name);
1104 newArgSyms.push_back(port.pi.sym);
1105 newArgLocations.push_back(port.pi.loc);
1106 newArgAnnotations.push_back(port.pi.annotations.getArrayAttr());
1108 newInternalPaths.push_back(port.internalPath.value_or(emptyInternalPath));
1111 newModuleAttrs.push_back(
1112 NamedAttribute(cache.sPortDirections,
1115 newModuleAttrs.push_back(
1116 NamedAttribute(cache.sPortNames, builder.getArrayAttr(newArgNames)));
1118 newModuleAttrs.push_back(
1119 NamedAttribute(cache.sPortTypes, builder.getArrayAttr(newArgTypes)));
1121 newModuleAttrs.push_back(NamedAttribute(
1122 cache.sPortLocations, builder.getArrayAttr(newArgLocations)));
1124 newModuleAttrs.push_back(NamedAttribute(
1125 cache.sPortAnnotations, builder.getArrayAttr(newArgAnnotations)));
1128 extModule->setAttrs(newModuleAttrs);
1129 FModuleLike::fixupPortSymsArray(newArgSyms, context);
1130 extModule.setPortSymbols(newArgSyms);
1132 extModule.setInternalPathsAttr(builder.getArrayAttr(newInternalPaths));
1137 bool TypeLoweringVisitor::visitDecl(FModuleOp module) {
1138 auto *body = module.getBodyBlock();
1140 ImplicitLocOpBuilder theBuilder(module.getLoc(), context);
1141 builder = &theBuilder;
1147 llvm::BitVector argsToRemove;
1148 auto newArgs = llvm::map_to_vector(module.getPorts(), [](
auto pi) {
1149 return PortInfoWithIP{pi, std::nullopt};
1152 size_t argsRemoved = 0;
1153 for (
size_t argIndex = 0; argIndex < newArgs.size(); ++argIndex) {
1154 SmallVector<Value> lowerings;
1155 if (lowerArg(module, argIndex, argsRemoved, newArgs, lowerings)) {
1156 auto arg = module.getArgument(argIndex);
1157 processUsers(arg, lowerings);
1158 argsToRemove.push_back(
true);
1161 argsToRemove.push_back(
false);
1166 if (argsRemoved != 0) {
1167 body->eraseArguments(argsToRemove);
1168 size_t size = newArgs.size();
1169 for (
size_t src = 0, dst = 0; src < size; ++src) {
1170 if (argsToRemove[src])
1172 newArgs[dst] = newArgs[src];
1175 newArgs.erase(newArgs.end() - argsRemoved, newArgs.end());
1178 SmallVector<NamedAttribute, 8> newModuleAttrs;
1181 for (
auto attr : module->getAttrDictionary())
1184 if (attr.getName() !=
"portNames" && attr.getName() !=
"portDirections" &&
1185 attr.getName() !=
"portTypes" && attr.getName() !=
"portAnnotations" &&
1186 attr.getName() !=
"portSymbols" && attr.getName() !=
"portLocations")
1187 newModuleAttrs.push_back(attr);
1189 SmallVector<Direction> newArgDirections;
1190 SmallVector<Attribute> newArgNames;
1191 SmallVector<Attribute> newArgTypes;
1192 SmallVector<Attribute> newArgSyms;
1193 SmallVector<Attribute> newArgLocations;
1194 SmallVector<Attribute, 8> newArgAnnotations;
1195 for (
auto &port : newArgs) {
1196 newArgDirections.push_back(port.pi.direction);
1197 newArgNames.push_back(port.pi.name);
1199 newArgSyms.push_back(port.pi.sym);
1200 newArgLocations.push_back(port.pi.loc);
1201 newArgAnnotations.push_back(port.pi.annotations.getArrayAttr());
1204 newModuleAttrs.push_back(
1205 NamedAttribute(cache.sPortDirections,
1208 newModuleAttrs.push_back(
1209 NamedAttribute(cache.sPortNames, builder->getArrayAttr(newArgNames)));
1211 newModuleAttrs.push_back(
1212 NamedAttribute(cache.sPortTypes, builder->getArrayAttr(newArgTypes)));
1214 newModuleAttrs.push_back(NamedAttribute(
1215 cache.sPortLocations, builder->getArrayAttr(newArgLocations)));
1217 newModuleAttrs.push_back(NamedAttribute(
1218 cache.sPortAnnotations, builder->getArrayAttr(newArgAnnotations)));
1221 module->setAttrs(newModuleAttrs);
1222 FModuleLike::fixupPortSymsArray(newArgSyms, context);
1223 module.setPortSymbols(newArgSyms);
1228 bool TypeLoweringVisitor::visitDecl(WireOp op) {
1229 if (op.isForceable())
1232 auto clone = [&](
const FlatBundleFieldEntry &field,
1233 ArrayAttr attrs) -> Value {
1235 ->create<WireOp>(
mapLoweredType(op.getDataRaw().getType(), field.type),
1236 "", NameKindEnum::DroppableName, attrs, StringAttr{})
1239 return lowerProducer(op, clone);
1243 bool TypeLoweringVisitor::visitDecl(RegOp op) {
1244 if (op.isForceable())
1247 auto clone = [&](
const FlatBundleFieldEntry &field,
1248 ArrayAttr attrs) -> Value {
1250 ->create<RegOp>(field.type, op.getClockVal(),
"",
1251 NameKindEnum::DroppableName, attrs, StringAttr{})
1254 return lowerProducer(op, clone);
1258 bool TypeLoweringVisitor::visitDecl(RegResetOp op) {
1259 if (op.isForceable())
1262 auto clone = [&](
const FlatBundleFieldEntry &field,
1263 ArrayAttr attrs) -> Value {
1264 auto resetVal = getSubWhatever(op.getResetValue(), field.index);
1266 ->create<RegResetOp>(field.type, op.getClockVal(), op.getResetSignal(),
1267 resetVal,
"", NameKindEnum::DroppableName, attrs,
1271 return lowerProducer(op, clone);
1275 bool TypeLoweringVisitor::visitDecl(NodeOp op) {
1276 if (op.isForceable())
1279 auto clone = [&](
const FlatBundleFieldEntry &field,
1280 ArrayAttr attrs) -> Value {
1281 auto input = getSubWhatever(op.getInput(), field.index);
1283 ->create<NodeOp>(input,
"", NameKindEnum::DroppableName, attrs)
1286 return lowerProducer(op, clone);
1290 bool TypeLoweringVisitor::visitExpr(InvalidValueOp op) {
1291 auto clone = [&](
const FlatBundleFieldEntry &field,
1292 ArrayAttr attrs) -> Value {
1293 return builder->create<InvalidValueOp>(field.type);
1295 return lowerProducer(op, clone);
1299 bool TypeLoweringVisitor::visitExpr(MuxPrimOp op) {
1300 auto clone = [&](
const FlatBundleFieldEntry &field,
1301 ArrayAttr attrs) -> Value {
1302 auto high = getSubWhatever(op.getHigh(), field.index);
1303 auto low = getSubWhatever(op.getLow(), field.index);
1304 return builder->create<MuxPrimOp>(op.getSel(), high, low);
1306 return lowerProducer(op, clone);
1310 bool TypeLoweringVisitor::visitExpr(Mux2CellIntrinsicOp op) {
1311 auto clone = [&](
const FlatBundleFieldEntry &field,
1312 ArrayAttr attrs) -> Value {
1313 auto high = getSubWhatever(op.getHigh(), field.index);
1314 auto low = getSubWhatever(op.getLow(), field.index);
1315 return builder->create<Mux2CellIntrinsicOp>(op.getSel(), high, low);
1317 return lowerProducer(op, clone);
1321 bool TypeLoweringVisitor::visitExpr(Mux4CellIntrinsicOp op) {
1322 auto clone = [&](
const FlatBundleFieldEntry &field,
1323 ArrayAttr attrs) -> Value {
1324 auto v3 = getSubWhatever(op.getV3(), field.index);
1325 auto v2 = getSubWhatever(op.getV2(), field.index);
1326 auto v1 = getSubWhatever(op.getV1(), field.index);
1327 auto v0 = getSubWhatever(op.getV0(), field.index);
1328 return builder->create<Mux4CellIntrinsicOp>(op.getSel(), v3, v2, v1, v0);
1330 return lowerProducer(op, clone);
1334 bool TypeLoweringVisitor::visitUnrealizedConversionCast(
1335 mlir::UnrealizedConversionCastOp op) {
1336 auto clone = [&](
const FlatBundleFieldEntry &field,
1337 ArrayAttr attrs) -> Value {
1338 auto input = getSubWhatever(op.getOperand(0), field.index);
1339 return builder->create<mlir::UnrealizedConversionCastOp>(field.type, input)
1344 if (!type_isa<FIRRTLType>(op->getOperand(0).getType()))
1346 return lowerProducer(op, clone);
1350 bool TypeLoweringVisitor::visitExpr(BitCastOp op) {
1351 Value srcLoweredVal = op.getInput();
1355 SmallVector<FlatBundleFieldEntry> fields;
1356 if (
peelType(op.getInput().getType(), fields, PreserveAggregate::None)) {
1357 size_t uptoBits = 0;
1360 for (
const auto &field : llvm::enumerate(fields)) {
1361 auto fieldBitwidth = *
getBitWidth(field.value().type);
1363 if (fieldBitwidth == 0)
1365 Value src = getSubWhatever(op.getInput(), field.index());
1367 src = builder->createOrFold<BitCastOp>(
1371 srcLoweredVal = src;
1373 if (type_isa<BundleType>(op.getInput().getType())) {
1374 srcLoweredVal = builder->create<CatPrimOp>(srcLoweredVal, src);
1376 srcLoweredVal = builder->create<CatPrimOp>(src, srcLoweredVal);
1380 uptoBits += fieldBitwidth;
1383 srcLoweredVal = builder->createOrFold<AsUIntPrimOp>(srcLoweredVal);
1387 if (type_isa<BundleType, FVectorType>(op.getResult().getType())) {
1389 size_t uptoBits = 0;
1390 auto aggregateBits = *
getBitWidth(op.getResult().getType());
1391 auto clone = [&](
const FlatBundleFieldEntry &field,
1392 ArrayAttr attrs) -> Value {
1398 return builder->create<InvalidValueOp>(field.type);
1403 if (type_isa<BundleType>(op.getResult().getType())) {
1405 srcLoweredVal, aggregateBits - uptoBits - 1,
1406 aggregateBits - uptoBits - fieldBits);
1409 srcLoweredVal, uptoBits + fieldBits - 1, uptoBits);
1411 uptoBits += fieldBits;
1412 return builder->create<BitCastOp>(field.type,
extractBits);
1414 return lowerProducer(op, clone);
1418 if (type_isa<SIntType>(op.getType()))
1419 srcLoweredVal = builder->create<AsSIntPrimOp>(srcLoweredVal);
1420 op.getResult().replaceAllUsesWith(srcLoweredVal);
1424 bool TypeLoweringVisitor::visitExpr(RefSendOp op) {
1425 auto clone = [&](
const FlatBundleFieldEntry &field,
1426 ArrayAttr attrs) -> Value {
1427 return builder->create<RefSendOp>(
1428 getSubWhatever(op.getBase(), field.index));
1433 return lowerProducer(op, clone);
1436 bool TypeLoweringVisitor::visitExpr(RefResolveOp op) {
1437 auto clone = [&](
const FlatBundleFieldEntry &field,
1438 ArrayAttr attrs) -> Value {
1439 Value src = getSubWhatever(op.getRef(), field.index);
1440 return builder->create<RefResolveOp>(src);
1444 return lowerProducer(op, clone, op.getRef().getType());
1447 bool TypeLoweringVisitor::visitExpr(RefCastOp op) {
1448 auto clone = [&](
const FlatBundleFieldEntry &field,
1449 ArrayAttr attrs) -> Value {
1450 auto input = getSubWhatever(op.getInput(), field.index);
1451 return builder->create<RefCastOp>(
RefType::get(field.type,
1452 op.getType().getForceable(),
1453 op.getType().getLayer()),
1456 return lowerProducer(op, clone);
1459 bool TypeLoweringVisitor::visitDecl(InstanceOp op) {
1461 SmallVector<Type, 8> resultTypes;
1462 SmallVector<int64_t, 8> endFields;
1463 auto oldPortAnno = op.getPortAnnotations();
1464 SmallVector<Direction> newDirs;
1465 SmallVector<Attribute> newNames;
1466 SmallVector<Attribute> newPortAnno;
1468 cast<FModuleLike>(op.getReferencedOperation(symTbl)));
1470 endFields.push_back(0);
1471 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
1472 auto srcType = type_cast<FIRRTLType>(op.getType(i));
1475 SmallVector<FlatBundleFieldEntry, 8> fieldTypes;
1476 if (!
peelType(srcType, fieldTypes, mode)) {
1477 newDirs.push_back(op.getPortDirection(i));
1478 newNames.push_back(op.getPortName(i));
1479 resultTypes.push_back(srcType);
1480 newPortAnno.push_back(oldPortAnno[i]);
1483 auto oldName = op.getPortNameStr(i);
1484 auto oldDir = op.getPortDirection(i);
1486 for (
const auto &field : fieldTypes) {
1487 newDirs.push_back(
direction::get((
unsigned)oldDir ^ field.isOutput));
1488 newNames.push_back(builder->getStringAttr(oldName + field.suffix));
1490 auto annos = filterAnnotations(
1491 context, dyn_cast_or_null<ArrayAttr>(oldPortAnno[i]), srcType,
1493 newPortAnno.push_back(annos);
1496 endFields.push_back(resultTypes.size());
1506 auto newInstance = builder->create<InstanceOp>(
1507 resultTypes, op.getModuleNameAttr(), op.getNameAttr(),
1509 builder->getArrayAttr(newNames), op.getAnnotations(),
1510 builder->getArrayAttr(newPortAnno), op.getLayersAttr(),
1511 op.getLowerToBindAttr(),
1514 newInstance->setDiscardableAttrs(op->getDiscardableAttrDictionary());
1516 SmallVector<Value> lowered;
1517 for (
size_t aggIndex = 0, eAgg = op.getNumResults(); aggIndex != eAgg;
1520 for (
size_t fieldIndex = endFields[aggIndex],
1521 eField = endFields[aggIndex + 1];
1522 fieldIndex < eField; ++fieldIndex)
1523 lowered.push_back(newInstance.getResult(fieldIndex));
1524 if (lowered.size() != 1 ||
1525 op.getType(aggIndex) != resultTypes[endFields[aggIndex]])
1526 processUsers(op.getResult(aggIndex), lowered);
1528 op.getResult(aggIndex).replaceAllUsesWith(lowered[0]);
1533 bool TypeLoweringVisitor::visitExpr(SubaccessOp op) {
1534 auto input = op.getInput();
1535 FVectorType vType = input.getType();
1538 if (vType.getNumElements() == 0) {
1539 Value inv = builder->create<InvalidValueOp>(vType.getElementType());
1540 op.replaceAllUsesWith(inv);
1545 if (ConstantOp arg =
1546 llvm::dyn_cast_or_null<ConstantOp>(op.getIndex().getDefiningOp())) {
1547 auto sio = builder->create<SubindexOp>(op.getInput(),
1548 arg.getValue().getExtValue());
1549 op.replaceAllUsesWith(sio.getResult());
1554 SmallVector<Value> inputs;
1555 inputs.reserve(vType.getNumElements());
1556 for (
int index = vType.getNumElements() - 1; index >= 0; index--)
1557 inputs.push_back(builder->create<SubindexOp>(input, index));
1559 Value multibitMux = builder->create<MultibitMuxOp>(op.getIndex(), inputs);
1560 op.replaceAllUsesWith(multibitMux);
1564 bool TypeLoweringVisitor::visitExpr(VectorCreateOp op) {
1565 auto clone = [&](
const FlatBundleFieldEntry &field,
1566 ArrayAttr attrs) -> Value {
1567 return op.getOperand(field.index);
1569 return lowerProducer(op, clone);
1572 bool TypeLoweringVisitor::visitExpr(BundleCreateOp op) {
1573 auto clone = [&](
const FlatBundleFieldEntry &field,
1574 ArrayAttr attrs) -> Value {
1575 return op.getOperand(field.index);
1577 return lowerProducer(op, clone);
1580 bool TypeLoweringVisitor::visitExpr(ElementwiseOrPrimOp op) {
1581 auto clone = [&](
const FlatBundleFieldEntry &field,
1582 ArrayAttr attrs) -> Value {
1583 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1584 getSubWhatever(op.getRhs(), field.index)};
1585 return type_isa<BundleType, FVectorType>(field.type)
1586 ? (Value)builder->create<ElementwiseOrPrimOp>(field.type,
1588 : (Value)builder->create<OrPrimOp>(operands);
1591 return lowerProducer(op, clone);
1594 bool TypeLoweringVisitor::visitExpr(ElementwiseAndPrimOp op) {
1595 auto clone = [&](
const FlatBundleFieldEntry &field,
1596 ArrayAttr attrs) -> Value {
1597 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1598 getSubWhatever(op.getRhs(), field.index)};
1599 return type_isa<BundleType, FVectorType>(field.type)
1600 ? (Value)builder->create<ElementwiseAndPrimOp>(field.type,
1602 : (Value)builder->create<AndPrimOp>(operands);
1605 return lowerProducer(op, clone);
1608 bool TypeLoweringVisitor::visitExpr(ElementwiseXorPrimOp op) {
1609 auto clone = [&](
const FlatBundleFieldEntry &field,
1610 ArrayAttr attrs) -> Value {
1611 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1612 getSubWhatever(op.getRhs(), field.index)};
1613 return type_isa<BundleType, FVectorType>(field.type)
1614 ? (Value)builder->create<ElementwiseXorPrimOp>(field.type,
1616 : (Value)builder->create<XorPrimOp>(operands);
1619 return lowerProducer(op, clone);
1622 bool TypeLoweringVisitor::visitExpr(MultibitMuxOp op) {
1623 auto clone = [&](
const FlatBundleFieldEntry &field,
1624 ArrayAttr attrs) -> Value {
1625 SmallVector<Value> newInputs;
1626 newInputs.reserve(op.getInputs().size());
1627 for (
auto input : op.getInputs()) {
1628 auto inputSub = getSubWhatever(input, field.index);
1629 newInputs.push_back(inputSub);
1631 return builder->create<MultibitMuxOp>(op.getIndex(), newInputs);
1633 return lowerProducer(op, clone);
1641 struct LowerTypesPass
1642 :
public circt::firrtl::impl::LowerFIRRTLTypesBase<LowerTypesPass> {
1646 preserveAggregate = preserveAggregateFlag;
1647 preserveMemories = preserveMemoriesFlag;
1649 void runOnOperation()
override;
1654 void LowerTypesPass::runOnOperation() {
1656 std::vector<FModuleLike> ops;
1658 auto &symTbl = getAnalysis<SymbolTable>();
1660 AttrCache cache(&getContext());
1662 DenseMap<FModuleLike, Convention> conventionTable;
1663 auto circuit = getOperation();
1664 for (
auto module : circuit.getOps<FModuleLike>()) {
1665 conventionTable.insert({module, module.getConvention()});
1666 ops.push_back(module);
1670 auto lowerModules = [&](FModuleLike op) -> LogicalResult {
1672 Convention convention = Convention::Internal;
1673 if (
auto conventionAttr = dyn_cast_or_null<ConventionAttr>(
1674 op->getDiscardableAttr(
"body_type_lowering")))
1675 convention = conventionAttr.getValue();
1678 TypeLoweringVisitor(&getContext(), preserveAggregate, convention,
1679 preserveMemories, symTbl, cache, conventionTable);
1682 return LogicalResult::failure(tl.isFailed());
1685 auto result = failableParallelForEach(&getContext(), ops, lowerModules);
1688 signalPassFailure();
1695 return std::make_unique<LowerTypesPass>(mode, memoryMode);
assert(baseType &&"element must be base type")
static SmallVector< Value > extractBits(ConversionPatternRewriter &rewriter, Value val)
static void dump(DIModule &module, raw_indented_ostream &os)
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.