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(), b->getArrayAttr(portNames),
257 (op.getName() + field.suffix).str(), op.getNameKind(),
258 op.getAnnotations(), op.getPortAnnotations(), op.getInnerSymAttr(),
259 op.getInitAttr(), op.getPrefixAttr());
261 if (op.getInnerSym()) {
262 op.emitError(
"cannot split memory with symbol present");
266 SmallVector<Attribute> newAnnotations;
267 for (
size_t portIdx = 0, e = newMem.getNumResults(); portIdx < e; ++portIdx) {
268 auto portType = type_cast<BundleType>(newMem.getResult(portIdx).getType());
269 auto oldPortType = type_cast<BundleType>(op.getResult(portIdx).getType());
270 SmallVector<Attribute> portAnno;
271 for (
auto attr : newMem.getPortAnnotation(portIdx)) {
274 auto targetIndex = oldPortType.getIndexForFieldID(annoFieldID);
278 if (annoFieldID == oldPortType.getFieldID(targetIndex)) {
281 b->getI32IntegerAttr(portType.getFieldID(targetIndex)));
282 portAnno.push_back(anno.
getDict());
287 if (type_isa<BundleType>(oldPortType.getElement(targetIndex).type)) {
292 auto fieldID = field.fieldID + oldPortType.getFieldID(targetIndex);
293 if (annoFieldID >= fieldID &&
298 annoFieldID - fieldID + portType.getFieldID(targetIndex);
299 anno.
setMember(
"circt.fieldID", b->getI32IntegerAttr(newFieldID));
300 portAnno.push_back(anno.
getDict());
304 portAnno.push_back(attr);
306 newAnnotations.push_back(b->getArrayAttr(portAnno));
308 newMem.setAllPortAnnotations(newAnnotations);
318 AttrCache(MLIRContext *context) {
330 AttrCache(
const AttrCache &) =
default;
333 StringAttr nameAttr, nameKindAttr, sPortDirections, sPortNames, sPortTypes,
334 sPortSymbols, sPortLocations, sPortAnnotations, sEmpty;
339 struct TypeLoweringVisitor :
public FIRRTLVisitor<TypeLoweringVisitor, bool> {
344 SymbolTable &symTbl,
const AttrCache &cache,
345 const llvm::DenseMap<FModuleLike, Convention> &conventionTable)
346 : context(context), aggregatePreservationMode(preserveAggregate),
347 memoryPreservationMode(memoryPreservationMode), symTbl(symTbl),
348 cache(cache), conventionTable(conventionTable) {}
355 void lowerModule(FModuleLike op);
357 bool lowerArg(FModuleLike module,
size_t argIndex,
size_t argsRemoved,
358 SmallVectorImpl<PortInfoWithIP> &newArgs,
359 SmallVectorImpl<Value> &lowering);
360 std::pair<Value, PortInfoWithIP>
361 addArg(Operation *module,
unsigned insertPt,
unsigned insertPtOffset,
362 FIRRTLType srcType,
const FlatBundleFieldEntry &field,
363 PortInfoWithIP &oldArg, hw::InnerSymAttr newSym);
366 bool visitDecl(FExtModuleOp op);
367 bool visitDecl(FModuleOp op);
368 bool visitDecl(InstanceOp op);
369 bool visitDecl(MemOp op);
370 bool visitDecl(NodeOp op);
371 bool visitDecl(RegOp op);
372 bool visitDecl(WireOp op);
373 bool visitDecl(RegResetOp op);
374 bool visitExpr(InvalidValueOp op);
375 bool visitExpr(SubaccessOp op);
376 bool visitExpr(VectorCreateOp op);
377 bool visitExpr(BundleCreateOp op);
378 bool visitExpr(ElementwiseAndPrimOp op);
379 bool visitExpr(ElementwiseOrPrimOp op);
380 bool visitExpr(ElementwiseXorPrimOp op);
381 bool visitExpr(MultibitMuxOp op);
382 bool visitExpr(MuxPrimOp op);
383 bool visitExpr(Mux2CellIntrinsicOp op);
384 bool visitExpr(Mux4CellIntrinsicOp op);
385 bool visitExpr(BitCastOp op);
386 bool visitExpr(RefSendOp op);
387 bool visitExpr(RefResolveOp op);
388 bool visitExpr(RefCastOp op);
389 bool visitStmt(ConnectOp op);
390 bool visitStmt(MatchingConnectOp op);
391 bool visitStmt(RefDefineOp op);
392 bool visitStmt(WhenOp op);
393 bool visitStmt(LayerBlockOp op);
394 bool visitUnrealizedConversionCast(mlir::UnrealizedConversionCastOp op);
396 bool isFailed()
const {
return encounteredError; }
398 bool visitInvalidOp(Operation *op) {
399 if (
auto castOp = dyn_cast<mlir::UnrealizedConversionCastOp>(op))
400 return visitUnrealizedConversionCast(castOp);
405 void processUsers(Value val, ArrayRef<Value> mapping);
406 bool processSAPath(Operation *);
407 void lowerBlock(Block *);
408 void lowerSAWritePath(Operation *, ArrayRef<Operation *> writePath);
418 llvm::function_ref<Value(
const FlatBundleFieldEntry &, ArrayAttr)> clone,
423 ArrayAttr filterAnnotations(MLIRContext *
ctxt, ArrayAttr annotations,
424 FIRRTLType srcType, FlatBundleFieldEntry field);
428 LogicalResult partitionSymbols(hw::InnerSymAttr sym,
FIRRTLType parentType,
429 SmallVectorImpl<hw::InnerSymAttr> &newSyms,
433 getPreservationModeForModule(FModuleLike moduleLike);
434 Value getSubWhatever(Value val,
size_t index);
436 size_t uniqueIdx = 0;
437 std::string uniqueName() {
438 auto myID = uniqueIdx++;
439 return (Twine(
"__GEN_") + Twine(myID)).str();
442 MLIRContext *context;
449 ImplicitLocOpBuilder *builder;
455 const AttrCache &cache;
457 const llvm::DenseMap<FModuleLike, Convention> &conventionTable;
460 bool encounteredError =
false;
467 TypeLoweringVisitor::getPreservationModeForModule(FModuleLike module) {
468 auto lookup = conventionTable.find(module);
469 if (lookup == conventionTable.end())
470 return aggregatePreservationMode;
471 switch (lookup->second) {
472 case Convention::Scalarized:
474 case Convention::Internal:
475 return aggregatePreservationMode;
477 llvm_unreachable(
"Unknown convention");
478 return aggregatePreservationMode;
481 Value TypeLoweringVisitor::getSubWhatever(Value val,
size_t index) {
482 if (type_isa<BundleType>(val.getType()))
483 return builder->create<SubfieldOp>(val, index);
484 if (type_isa<FVectorType>(val.getType()))
485 return builder->create<SubindexOp>(val, index);
486 if (type_isa<RefType>(val.getType()))
487 return builder->create<RefSubOp>(val, index);
488 llvm_unreachable(
"Unknown aggregate type");
493 bool TypeLoweringVisitor::processSAPath(Operation *op) {
496 if (writePath.empty())
499 lowerSAWritePath(op, writePath);
502 op->eraseOperands(0, 2);
504 for (
size_t i = 0; i < writePath.size(); ++i) {
505 if (writePath[i]->use_empty()) {
506 writePath[i]->erase();
514 void TypeLoweringVisitor::lowerBlock(Block *block) {
516 for (
auto it = block->rbegin(), e = block->rend(); it != e;) {
518 builder->setInsertionPoint(&iop);
519 builder->setLoc(iop.getLoc());
520 bool removeOp = dispatchVisitor(&iop);
529 ArrayAttr TypeLoweringVisitor::filterAnnotations(MLIRContext *
ctxt,
530 ArrayAttr annotations,
532 FlatBundleFieldEntry field) {
533 SmallVector<Attribute> retval;
534 if (!annotations || annotations.empty())
536 for (
auto opAttr : annotations) {
538 auto fieldID = anno.getFieldID();
539 anno.removeMember(
"circt.fieldID");
544 retval.push_back(anno.getAttr());
549 if (fieldID < field.fieldID ||
554 if (
auto newFieldID = fieldID - field.fieldID) {
557 anno.setMember(
"circt.fieldID", builder->getI32IntegerAttr(newFieldID));
560 retval.push_back(anno.getAttr());
565 LogicalResult TypeLoweringVisitor::partitionSymbols(
567 SmallVectorImpl<hw::InnerSymAttr> &newSyms, Location errorLoc) {
570 if (!sym || sym.empty())
573 auto *context = sym.getContext();
577 return mlir::emitError(errorLoc,
578 "unable to partition symbol on unsupported type ")
581 return TypeSwitch<FIRRTLType, LogicalResult>(baseType)
582 .Case<BundleType, FVectorType>([&](
auto aggType) -> LogicalResult {
586 hw::InnerSymPropertiesAttr prop;
590 SmallVector<BinningInfo> binning;
591 for (
auto prop : sym) {
592 auto fieldID = prop.getFieldID();
595 return mlir::emitError(errorLoc,
"unable to lower due to symbol ")
597 <<
" with target not preserved by lowering";
598 auto [index, relFieldID] = aggType.getIndexAndSubfieldID(fieldID);
599 binning.push_back({index, relFieldID, prop});
603 llvm::stable_sort(binning, [&](
auto &lhs,
auto &rhs) {
604 return std::tuple(lhs.index, lhs.relFieldID) <
605 std::tuple(rhs.index, rhs.relFieldID);
610 newSyms.resize(aggType.getNumElements());
611 for (
auto binIt = binning.begin(), binEnd = binning.end();
613 auto curIndex = binIt->index;
614 SmallVector<hw::InnerSymPropertiesAttr> propsForIndex;
616 while (binIt != binEnd && binIt->index == curIndex) {
618 context, binIt->prop.getName(), binIt->relFieldID,
619 binIt->prop.getSymVisibility()));
623 assert(!newSyms[curIndex]);
628 .Default([&](
auto ty) {
629 return mlir::emitError(
630 errorLoc,
"unable to partition symbol on unsupported type ")
635 bool TypeLoweringVisitor::lowerProducer(
637 llvm::function_ref<Value(
const FlatBundleFieldEntry &, ArrayAttr)> clone,
641 srcType = op->getResult(0).getType();
642 auto srcFType = type_dyn_cast<FIRRTLType>(srcType);
645 SmallVector<FlatBundleFieldEntry, 8> fieldTypes;
647 if (!
peelType(srcFType, fieldTypes, aggregatePreservationMode))
650 SmallVector<Value> lowered;
652 SmallString<16> loweredName;
653 auto nameKindAttr = op->getAttrOfType<NameKindEnumAttr>(cache.nameKindAttr);
655 if (
auto nameAttr = op->getAttrOfType<StringAttr>(cache.nameAttr))
656 loweredName = nameAttr.getValue();
657 auto baseNameLen = loweredName.size();
658 auto oldAnno = dyn_cast_or_null<ArrayAttr>(op->getAttr(
"annotations"));
660 SmallVector<hw::InnerSymAttr> fieldSyms(fieldTypes.size());
661 if (
auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(op)) {
662 if (failed(partitionSymbols(symOp.getInnerSymAttr(), srcFType, fieldSyms,
664 encounteredError =
true;
669 for (
const auto &[field, sym] : llvm::zip_equal(fieldTypes, fieldSyms)) {
670 if (!loweredName.empty()) {
671 loweredName.resize(baseNameLen);
672 loweredName += field.suffix;
677 ArrayAttr loweredAttrs =
678 filterAnnotations(context, oldAnno, srcFType, field);
679 auto newVal = clone(field, loweredAttrs);
685 auto newSymOp = newVal.getDefiningOp<hw::InnerSymbolOpInterface>();
688 "op with inner symbol lowered to op that cannot take inner symbol");
689 newSymOp.setInnerSymbolAttr(sym);
693 if (
auto *newOp = newVal.getDefiningOp()) {
694 if (!loweredName.empty())
697 newOp->setAttr(cache.nameKindAttr, nameKindAttr);
699 lowered.push_back(newVal);
702 processUsers(op->getResult(0), lowered);
706 void TypeLoweringVisitor::processUsers(Value val, ArrayRef<Value> mapping) {
707 for (
auto *user : llvm::make_early_inc_range(val.getUsers())) {
708 TypeSwitch<Operation *, void>(user)
709 .Case<SubindexOp>([mapping](SubindexOp sio) {
710 Value repl = mapping[sio.getIndex()];
711 sio.replaceAllUsesWith(repl);
714 .Case<SubfieldOp>([mapping](SubfieldOp sfo) {
716 Value repl = mapping[sfo.getFieldIndex()];
717 sfo.replaceAllUsesWith(repl);
720 .Case<RefSubOp>([mapping](RefSubOp refSub) {
721 Value repl = mapping[refSub.getIndex()];
722 refSub.replaceAllUsesWith(repl);
725 .Default([&](
auto op) {
736 ImplicitLocOpBuilder b(user->getLoc(), user);
740 assert(llvm::none_of(mapping, [](
auto v) {
741 auto fbasetype = type_dyn_cast<FIRRTLBaseType>(v.getType());
742 return !fbasetype || fbasetype.containsReference();
746 TypeSwitch<Type, Value>(val.getType())
747 .template Case<FVectorType>([&](
auto vecType) {
748 return b.createOrFold<VectorCreateOp>(vecType, mapping);
750 .
template Case<BundleType>([&](
auto bundleType) {
751 return b.createOrFold<BundleCreateOp>(bundleType, mapping);
753 .Default([&](
auto _) -> Value {
return {}; });
755 user->emitError(
"unable to reconstruct source of type ")
757 encounteredError =
true;
760 user->replaceUsesOfWith(val, input);
765 void TypeLoweringVisitor::lowerModule(FModuleLike op) {
766 if (
auto module = llvm::dyn_cast<FModuleOp>(*op))
768 else if (
auto extModule = llvm::dyn_cast<FExtModuleOp>(*op))
769 visitDecl(extModule);
775 std::pair<Value, PortInfoWithIP>
776 TypeLoweringVisitor::addArg(Operation *module,
unsigned insertPt,
778 const FlatBundleFieldEntry &field,
779 PortInfoWithIP &oldArg, hw::InnerSymAttr newSym) {
782 if (
auto mod = llvm::dyn_cast<FModuleOp>(module)) {
783 Block *body = mod.getBodyBlock();
785 newValue = body->insertArgument(insertPt, fieldType, oldArg.pi.loc);
789 auto name = builder->getStringAttr(oldArg.pi.name.getValue() + field.suffix);
792 auto newAnnotations = filterAnnotations(
793 context, oldArg.pi.annotations.getArrayAttr(), srcType, field);
795 auto direction = (
Direction)((
unsigned)oldArg.pi.direction ^ field.isOutput);
797 return std::make_pair(
799 PortInfoWithIP{
PortInfo{name, fieldType, direction, newSym, oldArg.pi.loc,
801 oldArg.internalPath});
805 bool TypeLoweringVisitor::lowerArg(FModuleLike module,
size_t argIndex,
807 SmallVectorImpl<PortInfoWithIP> &newArgs,
808 SmallVectorImpl<Value> &lowering) {
811 SmallVector<FlatBundleFieldEntry> fieldTypes;
812 auto srcType = type_cast<FIRRTLType>(newArgs[argIndex].pi.type);
813 if (!
peelType(srcType, fieldTypes, getPreservationModeForModule(module)))
817 if (
auto ip = newArgs[argIndex].internalPath; ip && ip->getPath()) {
818 ::mlir::emitError(newArgs[argIndex].pi.loc,
819 "cannot lower port with internal path");
820 encounteredError =
true;
824 SmallVector<hw::InnerSymAttr> fieldSyms(fieldTypes.size());
825 if (failed(partitionSymbols(newArgs[argIndex].pi.sym, srcType, fieldSyms,
826 newArgs[argIndex].pi.loc))) {
827 encounteredError =
true;
831 for (
const auto &[idx, field, fieldSym] :
832 llvm::enumerate(fieldTypes, fieldSyms)) {
833 auto newValue = addArg(module, 1 + argIndex + idx, argsRemoved, srcType,
834 field, newArgs[argIndex], fieldSym);
835 newArgs.insert(newArgs.begin() + 1 + argIndex + idx, newValue.second);
837 lowering.push_back(newValue.first);
842 static Value
cloneAccess(ImplicitLocOpBuilder *builder, Operation *op,
844 if (
auto rop = llvm::dyn_cast<SubfieldOp>(op))
845 return builder->create<SubfieldOp>(rhs, rop.getFieldIndex());
846 if (
auto rop = llvm::dyn_cast<SubindexOp>(op))
847 return builder->create<SubindexOp>(rhs, rop.getIndex());
848 if (
auto rop = llvm::dyn_cast<SubaccessOp>(op))
849 return builder->create<SubaccessOp>(rhs, rop.getIndex());
850 op->emitError(
"Unknown accessor");
854 void TypeLoweringVisitor::lowerSAWritePath(Operation *op,
855 ArrayRef<Operation *> writePath) {
856 SubaccessOp sao = cast<SubaccessOp>(writePath.back());
857 FVectorType saoType = sao.getInput().getType();
858 auto selectWidth = llvm::Log2_64_Ceil(saoType.getNumElements());
860 for (
size_t index = 0, e = saoType.getNumElements(); index < e; ++index) {
861 auto cond = builder->create<EQPrimOp>(
863 builder->createOrFold<ConstantOp>(
UIntType::get(context, selectWidth),
864 APInt(selectWidth, index)));
865 builder->create<WhenOp>(cond,
false, [&]() {
867 Value leaf = builder->create<SubindexOp>(sao.getInput(), index);
868 for (
int i = writePath.size() - 2; i >= 0; --i) {
869 if (
auto access =
cloneAccess(builder, writePath[i], leaf))
872 encounteredError =
true;
883 bool TypeLoweringVisitor::visitStmt(ConnectOp op) {
884 if (processSAPath(op))
888 SmallVector<FlatBundleFieldEntry> fields;
895 for (
const auto &field : llvm::enumerate(fields)) {
896 Value src = getSubWhatever(op.getSrc(), field.index());
897 Value dest = getSubWhatever(op.getDest(), field.index());
898 if (field.value().isOutput)
899 std::swap(src, dest);
906 bool TypeLoweringVisitor::visitStmt(MatchingConnectOp op) {
907 if (processSAPath(op))
911 SmallVector<FlatBundleFieldEntry> fields;
918 for (
const auto &field : llvm::enumerate(fields)) {
919 Value src = getSubWhatever(op.getSrc(), field.index());
920 Value dest = getSubWhatever(op.getDest(), field.index());
921 if (field.value().isOutput)
922 std::swap(src, dest);
923 builder->create<MatchingConnectOp>(dest, src);
929 bool TypeLoweringVisitor::visitStmt(RefDefineOp op) {
931 SmallVector<FlatBundleFieldEntry> fields;
933 if (!
peelType(op.getDest().getType(), fields, aggregatePreservationMode))
937 for (
const auto &field : llvm::enumerate(fields)) {
938 Value src = getSubWhatever(op.getSrc(), field.index());
939 Value dest = getSubWhatever(op.getDest(), field.index());
940 assert(!field.value().isOutput &&
"unexpected flip in reftype destination");
941 builder->create<RefDefineOp>(dest, src);
946 bool TypeLoweringVisitor::visitStmt(WhenOp op) {
952 lowerBlock(&op.getThenBlock());
955 if (op.hasElseRegion())
956 lowerBlock(&op.getElseBlock());
961 bool TypeLoweringVisitor::visitStmt(LayerBlockOp op) {
962 lowerBlock(op.getBody());
968 bool TypeLoweringVisitor::visitDecl(MemOp op) {
970 SmallVector<FlatBundleFieldEntry> fields;
973 if (!
peelType(op.getDataType(), fields, memoryPreservationMode))
976 if (op.getInnerSym()) {
977 op->emitError() <<
"has a symbol, but no symbols may exist on aggregates "
978 "passed through LowerTypes";
979 encounteredError =
true;
983 SmallVector<MemOp> newMemories;
984 SmallVector<WireOp> oldPorts;
987 for (
unsigned int index = 0, end = op.getNumResults(); index < end; ++index) {
988 auto result = op.getResult(index);
989 if (op.getPortKind(index) == MemOp::PortKind::Debug) {
990 op.emitOpError(
"cannot lower memory with debug port");
991 encounteredError =
true;
994 auto wire = builder->create<WireOp>(
996 (op.getName() +
"_" + op.getPortName(index).getValue()).str());
997 oldPorts.push_back(wire);
998 result.replaceAllUsesWith(wire.getResult());
1005 for (
const auto &field : fields) {
1007 if (!newMemForField) {
1008 op.emitError(
"failed cloning memory for field");
1009 encounteredError =
true;
1012 newMemories.push_back(newMemForField);
1015 for (
size_t index = 0, rend = op.getNumResults(); index < rend; ++index) {
1016 auto result = oldPorts[index].getResult();
1017 auto rType = type_cast<BundleType>(result.getType());
1018 for (
size_t fieldIndex = 0, fend = rType.getNumElements();
1019 fieldIndex != fend; ++fieldIndex) {
1020 auto name = rType.getElement(fieldIndex).name.getValue();
1021 auto oldField = builder->create<SubfieldOp>(result, fieldIndex);
1024 if (name ==
"data" || name ==
"mask" || name ==
"wdata" ||
1025 name ==
"wmask" || name ==
"rdata") {
1026 for (
const auto &field : fields) {
1027 auto realOldField = getSubWhatever(oldField, field.index);
1028 auto newField = getSubWhatever(
1029 newMemories[field.index].getResult(index), fieldIndex);
1030 if (rType.getElement(fieldIndex).isFlip)
1031 std::swap(realOldField, newField);
1035 for (
auto mem : newMemories) {
1037 builder->create<SubfieldOp>(mem.getResult(index), fieldIndex);
1046 bool TypeLoweringVisitor::visitDecl(FExtModuleOp extModule) {
1047 ImplicitLocOpBuilder theBuilder(extModule.getLoc(), context);
1048 builder = &theBuilder;
1051 OpBuilder builder(context);
1053 auto internalPaths = extModule.getInternalPaths();
1056 SmallVector<unsigned> argsToRemove;
1057 SmallVector<PortInfoWithIP> newArgs;
1058 for (
auto [idx, pi] : llvm::enumerate(extModule.getPorts())) {
1059 std::optional<InternalPathAttr> internalPath;
1061 internalPath = cast<InternalPathAttr>(internalPaths->getValue()[idx]);
1062 newArgs.push_back({pi, internalPath});
1065 for (
size_t argIndex = 0, argsRemoved = 0; argIndex < newArgs.size();
1067 SmallVector<Value> lowering;
1068 if (lowerArg(extModule, argIndex, argsRemoved, newArgs, lowering)) {
1069 argsToRemove.push_back(argIndex);
1076 for (
auto toRemove : llvm::reverse(argsToRemove))
1077 newArgs.erase(newArgs.begin() + toRemove);
1079 SmallVector<NamedAttribute, 8> newModuleAttrs;
1082 for (
auto attr : extModule->getAttrDictionary())
1085 if (attr.getName() !=
"portDirections" && attr.getName() !=
"portNames" &&
1086 attr.getName() !=
"portTypes" && attr.getName() !=
"portAnnotations" &&
1087 attr.getName() !=
"portSymbols" && attr.getName() !=
"portLocations")
1088 newModuleAttrs.push_back(attr);
1090 SmallVector<Direction> newArgDirections;
1091 SmallVector<Attribute> newArgNames;
1092 SmallVector<Attribute, 8> newArgTypes;
1093 SmallVector<Attribute, 8> newArgSyms;
1094 SmallVector<Attribute, 8> newArgLocations;
1095 SmallVector<Attribute, 8> newArgAnnotations;
1096 SmallVector<Attribute, 8> newInternalPaths;
1099 for (
auto &port : newArgs) {
1100 newArgDirections.push_back(port.pi.direction);
1101 newArgNames.push_back(port.pi.name);
1103 newArgSyms.push_back(port.pi.sym);
1104 newArgLocations.push_back(port.pi.loc);
1105 newArgAnnotations.push_back(port.pi.annotations.getArrayAttr());
1107 newInternalPaths.push_back(port.internalPath.value_or(emptyInternalPath));
1110 newModuleAttrs.push_back(
1111 NamedAttribute(cache.sPortDirections,
1114 newModuleAttrs.push_back(
1115 NamedAttribute(cache.sPortNames, builder.getArrayAttr(newArgNames)));
1117 newModuleAttrs.push_back(
1118 NamedAttribute(cache.sPortTypes, builder.getArrayAttr(newArgTypes)));
1120 newModuleAttrs.push_back(NamedAttribute(
1121 cache.sPortLocations, builder.getArrayAttr(newArgLocations)));
1123 newModuleAttrs.push_back(NamedAttribute(
1124 cache.sPortAnnotations, builder.getArrayAttr(newArgAnnotations)));
1127 extModule->setAttrs(newModuleAttrs);
1128 FModuleLike::fixupPortSymsArray(newArgSyms, context);
1129 extModule.setPortSymbols(newArgSyms);
1131 extModule.setInternalPathsAttr(builder.getArrayAttr(newInternalPaths));
1136 bool TypeLoweringVisitor::visitDecl(FModuleOp module) {
1137 auto *body = module.getBodyBlock();
1139 ImplicitLocOpBuilder theBuilder(module.getLoc(), context);
1140 builder = &theBuilder;
1146 llvm::BitVector argsToRemove;
1147 auto newArgs = llvm::map_to_vector(module.getPorts(), [](
auto pi) {
1148 return PortInfoWithIP{pi, std::nullopt};
1151 size_t argsRemoved = 0;
1152 for (
size_t argIndex = 0; argIndex < newArgs.size(); ++argIndex) {
1153 SmallVector<Value> lowerings;
1154 if (lowerArg(module, argIndex, argsRemoved, newArgs, lowerings)) {
1155 auto arg = module.getArgument(argIndex);
1156 processUsers(arg, lowerings);
1157 argsToRemove.push_back(
true);
1160 argsToRemove.push_back(
false);
1165 if (argsRemoved != 0) {
1166 body->eraseArguments(argsToRemove);
1167 size_t size = newArgs.size();
1168 for (
size_t src = 0, dst = 0; src < size; ++src) {
1169 if (argsToRemove[src])
1171 newArgs[dst] = newArgs[src];
1174 newArgs.erase(newArgs.end() - argsRemoved, newArgs.end());
1177 SmallVector<NamedAttribute, 8> newModuleAttrs;
1180 for (
auto attr : module->getAttrDictionary())
1183 if (attr.getName() !=
"portNames" && attr.getName() !=
"portDirections" &&
1184 attr.getName() !=
"portTypes" && attr.getName() !=
"portAnnotations" &&
1185 attr.getName() !=
"portSymbols" && attr.getName() !=
"portLocations")
1186 newModuleAttrs.push_back(attr);
1188 SmallVector<Direction> newArgDirections;
1189 SmallVector<Attribute> newArgNames;
1190 SmallVector<Attribute> newArgTypes;
1191 SmallVector<Attribute> newArgSyms;
1192 SmallVector<Attribute> newArgLocations;
1193 SmallVector<Attribute, 8> newArgAnnotations;
1194 for (
auto &port : newArgs) {
1195 newArgDirections.push_back(port.pi.direction);
1196 newArgNames.push_back(port.pi.name);
1198 newArgSyms.push_back(port.pi.sym);
1199 newArgLocations.push_back(port.pi.loc);
1200 newArgAnnotations.push_back(port.pi.annotations.getArrayAttr());
1203 newModuleAttrs.push_back(
1204 NamedAttribute(cache.sPortDirections,
1207 newModuleAttrs.push_back(
1208 NamedAttribute(cache.sPortNames, builder->getArrayAttr(newArgNames)));
1210 newModuleAttrs.push_back(
1211 NamedAttribute(cache.sPortTypes, builder->getArrayAttr(newArgTypes)));
1213 newModuleAttrs.push_back(NamedAttribute(
1214 cache.sPortLocations, builder->getArrayAttr(newArgLocations)));
1216 newModuleAttrs.push_back(NamedAttribute(
1217 cache.sPortAnnotations, builder->getArrayAttr(newArgAnnotations)));
1220 module->setAttrs(newModuleAttrs);
1221 FModuleLike::fixupPortSymsArray(newArgSyms, context);
1222 module.setPortSymbols(newArgSyms);
1227 bool TypeLoweringVisitor::visitDecl(WireOp op) {
1228 if (op.isForceable())
1231 auto clone = [&](
const FlatBundleFieldEntry &field,
1232 ArrayAttr attrs) -> Value {
1234 ->create<WireOp>(
mapLoweredType(op.getDataRaw().getType(), field.type),
1235 "", NameKindEnum::DroppableName, attrs, StringAttr{})
1238 return lowerProducer(op, clone);
1242 bool TypeLoweringVisitor::visitDecl(RegOp op) {
1243 if (op.isForceable())
1246 auto clone = [&](
const FlatBundleFieldEntry &field,
1247 ArrayAttr attrs) -> Value {
1249 ->create<RegOp>(field.type, op.getClockVal(),
"",
1250 NameKindEnum::DroppableName, attrs, StringAttr{})
1253 return lowerProducer(op, clone);
1257 bool TypeLoweringVisitor::visitDecl(RegResetOp op) {
1258 if (op.isForceable())
1261 auto clone = [&](
const FlatBundleFieldEntry &field,
1262 ArrayAttr attrs) -> Value {
1263 auto resetVal = getSubWhatever(op.getResetValue(), field.index);
1265 ->create<RegResetOp>(field.type, op.getClockVal(), op.getResetSignal(),
1266 resetVal,
"", NameKindEnum::DroppableName, attrs,
1270 return lowerProducer(op, clone);
1274 bool TypeLoweringVisitor::visitDecl(NodeOp op) {
1275 if (op.isForceable())
1278 auto clone = [&](
const FlatBundleFieldEntry &field,
1279 ArrayAttr attrs) -> Value {
1280 auto input = getSubWhatever(op.getInput(), field.index);
1282 ->create<NodeOp>(input,
"", NameKindEnum::DroppableName, attrs)
1285 return lowerProducer(op, clone);
1289 bool TypeLoweringVisitor::visitExpr(InvalidValueOp op) {
1290 auto clone = [&](
const FlatBundleFieldEntry &field,
1291 ArrayAttr attrs) -> Value {
1292 return builder->create<InvalidValueOp>(field.type);
1294 return lowerProducer(op, clone);
1298 bool TypeLoweringVisitor::visitExpr(MuxPrimOp 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<MuxPrimOp>(op.getSel(), high, low);
1305 return lowerProducer(op, clone);
1309 bool TypeLoweringVisitor::visitExpr(Mux2CellIntrinsicOp op) {
1310 auto clone = [&](
const FlatBundleFieldEntry &field,
1311 ArrayAttr attrs) -> Value {
1312 auto high = getSubWhatever(op.getHigh(), field.index);
1313 auto low = getSubWhatever(op.getLow(), field.index);
1314 return builder->create<Mux2CellIntrinsicOp>(op.getSel(), high, low);
1316 return lowerProducer(op, clone);
1320 bool TypeLoweringVisitor::visitExpr(Mux4CellIntrinsicOp op) {
1321 auto clone = [&](
const FlatBundleFieldEntry &field,
1322 ArrayAttr attrs) -> Value {
1323 auto v3 = getSubWhatever(op.getV3(), field.index);
1324 auto v2 = getSubWhatever(op.getV2(), field.index);
1325 auto v1 = getSubWhatever(op.getV1(), field.index);
1326 auto v0 = getSubWhatever(op.getV0(), field.index);
1327 return builder->create<Mux4CellIntrinsicOp>(op.getSel(), v3, v2, v1, v0);
1329 return lowerProducer(op, clone);
1333 bool TypeLoweringVisitor::visitUnrealizedConversionCast(
1334 mlir::UnrealizedConversionCastOp op) {
1335 auto clone = [&](
const FlatBundleFieldEntry &field,
1336 ArrayAttr attrs) -> Value {
1337 auto input = getSubWhatever(op.getOperand(0), field.index);
1338 return builder->create<mlir::UnrealizedConversionCastOp>(field.type, input)
1343 if (!type_isa<FIRRTLType>(op->getOperand(0).getType()))
1345 return lowerProducer(op, clone);
1349 bool TypeLoweringVisitor::visitExpr(BitCastOp op) {
1350 Value srcLoweredVal = op.getInput();
1354 SmallVector<FlatBundleFieldEntry> fields;
1355 if (
peelType(op.getInput().getType(), fields, PreserveAggregate::None)) {
1356 size_t uptoBits = 0;
1359 for (
const auto &field : llvm::enumerate(fields)) {
1360 auto fieldBitwidth = *
getBitWidth(field.value().type);
1362 if (fieldBitwidth == 0)
1364 Value src = getSubWhatever(op.getInput(), field.index());
1366 src = builder->createOrFold<BitCastOp>(
1370 srcLoweredVal = src;
1372 if (type_isa<BundleType>(op.getInput().getType())) {
1373 srcLoweredVal = builder->create<CatPrimOp>(srcLoweredVal, src);
1375 srcLoweredVal = builder->create<CatPrimOp>(src, srcLoweredVal);
1379 uptoBits += fieldBitwidth;
1382 srcLoweredVal = builder->createOrFold<AsUIntPrimOp>(srcLoweredVal);
1386 if (type_isa<BundleType, FVectorType>(op.getResult().getType())) {
1388 size_t uptoBits = 0;
1389 auto aggregateBits = *
getBitWidth(op.getResult().getType());
1390 auto clone = [&](
const FlatBundleFieldEntry &field,
1391 ArrayAttr attrs) -> Value {
1397 return builder->create<InvalidValueOp>(field.type);
1402 if (type_isa<BundleType>(op.getResult().getType())) {
1404 srcLoweredVal, aggregateBits - uptoBits - 1,
1405 aggregateBits - uptoBits - fieldBits);
1408 srcLoweredVal, uptoBits + fieldBits - 1, uptoBits);
1410 uptoBits += fieldBits;
1411 return builder->create<BitCastOp>(field.type,
extractBits);
1413 return lowerProducer(op, clone);
1417 if (type_isa<SIntType>(op.getType()))
1418 srcLoweredVal = builder->create<AsSIntPrimOp>(srcLoweredVal);
1419 op.getResult().replaceAllUsesWith(srcLoweredVal);
1423 bool TypeLoweringVisitor::visitExpr(RefSendOp op) {
1424 auto clone = [&](
const FlatBundleFieldEntry &field,
1425 ArrayAttr attrs) -> Value {
1426 return builder->create<RefSendOp>(
1427 getSubWhatever(op.getBase(), field.index));
1432 return lowerProducer(op, clone);
1435 bool TypeLoweringVisitor::visitExpr(RefResolveOp op) {
1436 auto clone = [&](
const FlatBundleFieldEntry &field,
1437 ArrayAttr attrs) -> Value {
1438 Value src = getSubWhatever(op.getRef(), field.index);
1439 return builder->create<RefResolveOp>(src);
1443 return lowerProducer(op, clone, op.getRef().getType());
1446 bool TypeLoweringVisitor::visitExpr(RefCastOp op) {
1447 auto clone = [&](
const FlatBundleFieldEntry &field,
1448 ArrayAttr attrs) -> Value {
1449 auto input = getSubWhatever(op.getInput(), field.index);
1450 return builder->create<RefCastOp>(
RefType::get(field.type,
1451 op.getType().getForceable(),
1452 op.getType().getLayer()),
1455 return lowerProducer(op, clone);
1458 bool TypeLoweringVisitor::visitDecl(InstanceOp op) {
1460 SmallVector<Type, 8> resultTypes;
1461 SmallVector<int64_t, 8> endFields;
1462 auto oldPortAnno = op.getPortAnnotations();
1463 SmallVector<Direction> newDirs;
1464 SmallVector<Attribute> newNames;
1465 SmallVector<Attribute> newPortAnno;
1467 cast<FModuleLike>(op.getReferencedOperation(symTbl)));
1469 endFields.push_back(0);
1470 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
1471 auto srcType = type_cast<FIRRTLType>(op.getType(i));
1474 SmallVector<FlatBundleFieldEntry, 8> fieldTypes;
1475 if (!
peelType(srcType, fieldTypes, mode)) {
1476 newDirs.push_back(op.getPortDirection(i));
1477 newNames.push_back(op.getPortName(i));
1478 resultTypes.push_back(srcType);
1479 newPortAnno.push_back(oldPortAnno[i]);
1482 auto oldName = op.getPortNameStr(i);
1483 auto oldDir = op.getPortDirection(i);
1485 for (
const auto &field : fieldTypes) {
1486 newDirs.push_back(
direction::get((
unsigned)oldDir ^ field.isOutput));
1487 newNames.push_back(builder->getStringAttr(oldName + field.suffix));
1489 auto annos = filterAnnotations(
1490 context, dyn_cast_or_null<ArrayAttr>(oldPortAnno[i]), srcType,
1492 newPortAnno.push_back(annos);
1495 endFields.push_back(resultTypes.size());
1505 auto newInstance = builder->create<InstanceOp>(
1506 resultTypes, op.getModuleNameAttr(), op.getNameAttr(),
1508 builder->getArrayAttr(newNames), op.getAnnotations(),
1509 builder->getArrayAttr(newPortAnno), op.getLayersAttr(),
1510 op.getLowerToBindAttr(),
1515 auto attrNames = InstanceOp::getAttributeNames();
1516 DenseSet<StringRef> attrSet(attrNames.begin(), attrNames.end());
1517 SmallVector<NamedAttribute> newAttrs(newInstance->getAttrs());
1518 for (
auto i : llvm::make_filter_range(op->getAttrs(), [&](
auto namedAttr) {
1519 return !attrSet.count(namedAttr.getName());
1521 newAttrs.push_back(i);
1522 newInstance->setAttrs(newAttrs);
1524 SmallVector<Value> lowered;
1525 for (
size_t aggIndex = 0, eAgg = op.getNumResults(); aggIndex != eAgg;
1528 for (
size_t fieldIndex = endFields[aggIndex],
1529 eField = endFields[aggIndex + 1];
1530 fieldIndex < eField; ++fieldIndex)
1531 lowered.push_back(newInstance.getResult(fieldIndex));
1532 if (lowered.size() != 1 ||
1533 op.getType(aggIndex) != resultTypes[endFields[aggIndex]])
1534 processUsers(op.getResult(aggIndex), lowered);
1536 op.getResult(aggIndex).replaceAllUsesWith(lowered[0]);
1541 bool TypeLoweringVisitor::visitExpr(SubaccessOp op) {
1542 auto input = op.getInput();
1543 FVectorType vType = input.getType();
1546 if (vType.getNumElements() == 0) {
1547 Value inv = builder->create<InvalidValueOp>(vType.getElementType());
1548 op.replaceAllUsesWith(inv);
1553 if (ConstantOp arg =
1554 llvm::dyn_cast_or_null<ConstantOp>(op.getIndex().getDefiningOp())) {
1555 auto sio = builder->create<SubindexOp>(op.getInput(),
1556 arg.getValue().getExtValue());
1557 op.replaceAllUsesWith(sio.getResult());
1562 SmallVector<Value> inputs;
1563 inputs.reserve(vType.getNumElements());
1564 for (
int index = vType.getNumElements() - 1; index >= 0; index--)
1565 inputs.push_back(builder->create<SubindexOp>(input, index));
1567 Value multibitMux = builder->create<MultibitMuxOp>(op.getIndex(), inputs);
1568 op.replaceAllUsesWith(multibitMux);
1572 bool TypeLoweringVisitor::visitExpr(VectorCreateOp 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(BundleCreateOp op) {
1581 auto clone = [&](
const FlatBundleFieldEntry &field,
1582 ArrayAttr attrs) -> Value {
1583 return op.getOperand(field.index);
1585 return lowerProducer(op, clone);
1588 bool TypeLoweringVisitor::visitExpr(ElementwiseOrPrimOp op) {
1589 auto clone = [&](
const FlatBundleFieldEntry &field,
1590 ArrayAttr attrs) -> Value {
1591 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1592 getSubWhatever(op.getRhs(), field.index)};
1593 return type_isa<BundleType, FVectorType>(field.type)
1594 ? (Value)builder->create<ElementwiseOrPrimOp>(field.type,
1596 : (Value)builder->create<OrPrimOp>(operands);
1599 return lowerProducer(op, clone);
1602 bool TypeLoweringVisitor::visitExpr(ElementwiseAndPrimOp op) {
1603 auto clone = [&](
const FlatBundleFieldEntry &field,
1604 ArrayAttr attrs) -> Value {
1605 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1606 getSubWhatever(op.getRhs(), field.index)};
1607 return type_isa<BundleType, FVectorType>(field.type)
1608 ? (Value)builder->create<ElementwiseAndPrimOp>(field.type,
1610 : (Value)builder->create<AndPrimOp>(operands);
1613 return lowerProducer(op, clone);
1616 bool TypeLoweringVisitor::visitExpr(ElementwiseXorPrimOp op) {
1617 auto clone = [&](
const FlatBundleFieldEntry &field,
1618 ArrayAttr attrs) -> Value {
1619 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1620 getSubWhatever(op.getRhs(), field.index)};
1621 return type_isa<BundleType, FVectorType>(field.type)
1622 ? (Value)builder->create<ElementwiseXorPrimOp>(field.type,
1624 : (Value)builder->create<XorPrimOp>(operands);
1627 return lowerProducer(op, clone);
1630 bool TypeLoweringVisitor::visitExpr(MultibitMuxOp op) {
1631 auto clone = [&](
const FlatBundleFieldEntry &field,
1632 ArrayAttr attrs) -> Value {
1633 SmallVector<Value> newInputs;
1634 newInputs.reserve(op.getInputs().size());
1635 for (
auto input : op.getInputs()) {
1636 auto inputSub = getSubWhatever(input, field.index);
1637 newInputs.push_back(inputSub);
1639 return builder->create<MultibitMuxOp>(op.getIndex(), newInputs);
1641 return lowerProducer(op, clone);
1649 struct LowerTypesPass
1650 :
public circt::firrtl::impl::LowerFIRRTLTypesBase<LowerTypesPass> {
1654 preserveAggregate = preserveAggregateFlag;
1655 preserveMemories = preserveMemoriesFlag;
1657 void runOnOperation()
override;
1662 void LowerTypesPass::runOnOperation() {
1664 std::vector<FModuleLike> ops;
1666 auto &symTbl = getAnalysis<SymbolTable>();
1668 AttrCache cache(&getContext());
1670 DenseMap<FModuleLike, Convention> conventionTable;
1671 auto circuit = getOperation();
1672 for (
auto module : circuit.getOps<FModuleLike>()) {
1673 conventionTable.insert({module, module.getConvention()});
1674 ops.push_back(module);
1678 auto lowerModules = [&](FModuleLike op) -> LogicalResult {
1680 TypeLoweringVisitor(&getContext(), preserveAggregate, preserveMemories,
1681 symTbl, cache, conventionTable);
1684 return LogicalResult::failure(tl.isFailed());
1687 auto result = failableParallelForEach(&getContext(), ops, lowerModules);
1690 signalPassFailure();
1697 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.