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 sPortSymbols, 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() !=
"portSymbols" && 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 FModuleLike::fixupPortSymsArray(newArgSyms, context);
1128 extModule.setPortSymbols(newArgSyms);
1130 extModule.setInternalPathsAttr(builder.getArrayAttr(newInternalPaths));
1135 bool TypeLoweringVisitor::visitDecl(FModuleOp module) {
1136 auto *body = module.getBodyBlock();
1138 ImplicitLocOpBuilder theBuilder(module.getLoc(), context);
1139 builder = &theBuilder;
1145 llvm::BitVector argsToRemove;
1146 auto newArgs = llvm::map_to_vector(module.getPorts(), [](
auto pi) {
1147 return PortInfoWithIP{pi, std::nullopt};
1149 for (
size_t argIndex = 0, argsRemoved = 0; argIndex < newArgs.size();
1151 SmallVector<Value> lowerings;
1152 if (lowerArg(module, argIndex, argsRemoved, newArgs, lowerings)) {
1153 auto arg = module.getArgument(argIndex);
1154 processUsers(arg, lowerings);
1155 argsToRemove.push_back(
true);
1158 argsToRemove.push_back(
false);
1163 body->eraseArguments(argsToRemove);
1164 for (
auto deadArg = argsToRemove.find_last(); deadArg != -1;
1165 deadArg = argsToRemove.find_prev(deadArg))
1166 newArgs.erase(newArgs.begin() + deadArg);
1168 SmallVector<NamedAttribute, 8> newModuleAttrs;
1171 for (
auto attr : module->getAttrDictionary())
1174 if (attr.getName() !=
"portNames" && attr.getName() !=
"portDirections" &&
1175 attr.getName() !=
"portTypes" && attr.getName() !=
"portAnnotations" &&
1176 attr.getName() !=
"portSymbols" && attr.getName() !=
"portLocations")
1177 newModuleAttrs.push_back(attr);
1179 SmallVector<Direction> newArgDirections;
1180 SmallVector<Attribute> newArgNames;
1181 SmallVector<Attribute> newArgTypes;
1182 SmallVector<Attribute> newArgSyms;
1183 SmallVector<Attribute> newArgLocations;
1184 SmallVector<Attribute, 8> newArgAnnotations;
1185 for (
auto &port : newArgs) {
1186 newArgDirections.push_back(port.pi.direction);
1187 newArgNames.push_back(port.pi.name);
1189 newArgSyms.push_back(port.pi.sym);
1190 newArgLocations.push_back(port.pi.loc);
1191 newArgAnnotations.push_back(port.pi.annotations.getArrayAttr());
1194 newModuleAttrs.push_back(
1195 NamedAttribute(cache.sPortDirections,
1198 newModuleAttrs.push_back(
1199 NamedAttribute(cache.sPortNames, builder->getArrayAttr(newArgNames)));
1201 newModuleAttrs.push_back(
1202 NamedAttribute(cache.sPortTypes, builder->getArrayAttr(newArgTypes)));
1204 newModuleAttrs.push_back(NamedAttribute(
1205 cache.sPortLocations, builder->getArrayAttr(newArgLocations)));
1207 newModuleAttrs.push_back(NamedAttribute(
1208 cache.sPortAnnotations, builder->getArrayAttr(newArgAnnotations)));
1211 module->setAttrs(newModuleAttrs);
1212 FModuleLike::fixupPortSymsArray(newArgSyms, context);
1213 module.setPortSymbols(newArgSyms);
1218 bool TypeLoweringVisitor::visitDecl(WireOp op) {
1219 if (op.isForceable())
1222 auto clone = [&](
const FlatBundleFieldEntry &field,
1223 ArrayAttr attrs) -> Value {
1225 ->create<WireOp>(
mapLoweredType(op.getDataRaw().getType(), field.type),
1226 "", NameKindEnum::DroppableName, attrs, StringAttr{})
1229 return lowerProducer(op, clone);
1233 bool TypeLoweringVisitor::visitDecl(RegOp op) {
1234 if (op.isForceable())
1237 auto clone = [&](
const FlatBundleFieldEntry &field,
1238 ArrayAttr attrs) -> Value {
1240 ->create<RegOp>(field.type, op.getClockVal(),
"",
1241 NameKindEnum::DroppableName, attrs, StringAttr{})
1244 return lowerProducer(op, clone);
1248 bool TypeLoweringVisitor::visitDecl(RegResetOp op) {
1249 if (op.isForceable())
1252 auto clone = [&](
const FlatBundleFieldEntry &field,
1253 ArrayAttr attrs) -> Value {
1254 auto resetVal = getSubWhatever(op.getResetValue(), field.index);
1256 ->create<RegResetOp>(field.type, op.getClockVal(), op.getResetSignal(),
1257 resetVal,
"", NameKindEnum::DroppableName, attrs,
1261 return lowerProducer(op, clone);
1265 bool TypeLoweringVisitor::visitDecl(NodeOp op) {
1266 if (op.isForceable())
1269 auto clone = [&](
const FlatBundleFieldEntry &field,
1270 ArrayAttr attrs) -> Value {
1271 auto input = getSubWhatever(op.getInput(), field.index);
1273 ->create<NodeOp>(input,
"", NameKindEnum::DroppableName, attrs)
1276 return lowerProducer(op, clone);
1280 bool TypeLoweringVisitor::visitExpr(InvalidValueOp op) {
1281 auto clone = [&](
const FlatBundleFieldEntry &field,
1282 ArrayAttr attrs) -> Value {
1283 return builder->create<InvalidValueOp>(field.type);
1285 return lowerProducer(op, clone);
1289 bool TypeLoweringVisitor::visitExpr(MuxPrimOp op) {
1290 auto clone = [&](
const FlatBundleFieldEntry &field,
1291 ArrayAttr attrs) -> Value {
1292 auto high = getSubWhatever(op.getHigh(), field.index);
1293 auto low = getSubWhatever(op.getLow(), field.index);
1294 return builder->create<MuxPrimOp>(op.getSel(), high, low);
1296 return lowerProducer(op, clone);
1300 bool TypeLoweringVisitor::visitExpr(Mux2CellIntrinsicOp op) {
1301 auto clone = [&](
const FlatBundleFieldEntry &field,
1302 ArrayAttr attrs) -> Value {
1303 auto high = getSubWhatever(op.getHigh(), field.index);
1304 auto low = getSubWhatever(op.getLow(), field.index);
1305 return builder->create<Mux2CellIntrinsicOp>(op.getSel(), high, low);
1307 return lowerProducer(op, clone);
1311 bool TypeLoweringVisitor::visitExpr(Mux4CellIntrinsicOp op) {
1312 auto clone = [&](
const FlatBundleFieldEntry &field,
1313 ArrayAttr attrs) -> Value {
1314 auto v3 = getSubWhatever(op.getV3(), field.index);
1315 auto v2 = getSubWhatever(op.getV2(), field.index);
1316 auto v1 = getSubWhatever(op.getV1(), field.index);
1317 auto v0 = getSubWhatever(op.getV0(), field.index);
1318 return builder->create<Mux4CellIntrinsicOp>(op.getSel(), v3, v2, v1, v0);
1320 return lowerProducer(op, clone);
1324 bool TypeLoweringVisitor::visitUnrealizedConversionCast(
1325 mlir::UnrealizedConversionCastOp op) {
1326 auto clone = [&](
const FlatBundleFieldEntry &field,
1327 ArrayAttr attrs) -> Value {
1328 auto input = getSubWhatever(op.getOperand(0), field.index);
1329 return builder->create<mlir::UnrealizedConversionCastOp>(field.type, input)
1334 if (!type_isa<FIRRTLType>(op->getOperand(0).getType()))
1336 return lowerProducer(op, clone);
1340 bool TypeLoweringVisitor::visitExpr(BitCastOp op) {
1341 Value srcLoweredVal = op.getInput();
1345 SmallVector<FlatBundleFieldEntry> fields;
1346 if (
peelType(op.getInput().getType(), fields, PreserveAggregate::None)) {
1347 size_t uptoBits = 0;
1350 for (
const auto &field : llvm::enumerate(fields)) {
1351 auto fieldBitwidth = *
getBitWidth(field.value().type);
1353 if (fieldBitwidth == 0)
1355 Value src = getSubWhatever(op.getInput(), field.index());
1357 src = builder->createOrFold<BitCastOp>(
1361 srcLoweredVal = src;
1363 if (type_isa<BundleType>(op.getInput().getType())) {
1364 srcLoweredVal = builder->create<CatPrimOp>(srcLoweredVal, src);
1366 srcLoweredVal = builder->create<CatPrimOp>(src, srcLoweredVal);
1370 uptoBits += fieldBitwidth;
1373 srcLoweredVal = builder->createOrFold<AsUIntPrimOp>(srcLoweredVal);
1377 if (type_isa<BundleType, FVectorType>(op.getResult().getType())) {
1379 size_t uptoBits = 0;
1380 auto aggregateBits = *
getBitWidth(op.getResult().getType());
1381 auto clone = [&](
const FlatBundleFieldEntry &field,
1382 ArrayAttr attrs) -> Value {
1388 return builder->create<InvalidValueOp>(field.type);
1393 if (type_isa<BundleType>(op.getResult().getType())) {
1395 srcLoweredVal, aggregateBits - uptoBits - 1,
1396 aggregateBits - uptoBits - fieldBits);
1399 srcLoweredVal, uptoBits + fieldBits - 1, uptoBits);
1401 uptoBits += fieldBits;
1402 return builder->create<BitCastOp>(field.type,
extractBits);
1404 return lowerProducer(op, clone);
1408 if (type_isa<SIntType>(op.getType()))
1409 srcLoweredVal = builder->create<AsSIntPrimOp>(srcLoweredVal);
1410 op.getResult().replaceAllUsesWith(srcLoweredVal);
1414 bool TypeLoweringVisitor::visitExpr(RefSendOp op) {
1415 auto clone = [&](
const FlatBundleFieldEntry &field,
1416 ArrayAttr attrs) -> Value {
1417 return builder->create<RefSendOp>(
1418 getSubWhatever(op.getBase(), field.index));
1423 return lowerProducer(op, clone);
1426 bool TypeLoweringVisitor::visitExpr(RefResolveOp op) {
1427 auto clone = [&](
const FlatBundleFieldEntry &field,
1428 ArrayAttr attrs) -> Value {
1429 Value src = getSubWhatever(op.getRef(), field.index);
1430 return builder->create<RefResolveOp>(src);
1434 return lowerProducer(op, clone, op.getRef().getType());
1437 bool TypeLoweringVisitor::visitExpr(RefCastOp op) {
1438 auto clone = [&](
const FlatBundleFieldEntry &field,
1439 ArrayAttr attrs) -> Value {
1440 auto input = getSubWhatever(op.getInput(), field.index);
1441 return builder->create<RefCastOp>(
RefType::get(field.type,
1442 op.getType().getForceable(),
1443 op.getType().getLayer()),
1446 return lowerProducer(op, clone);
1449 bool TypeLoweringVisitor::visitDecl(InstanceOp op) {
1451 SmallVector<Type, 8> resultTypes;
1452 SmallVector<int64_t, 8> endFields;
1453 auto oldPortAnno = op.getPortAnnotations();
1454 SmallVector<Direction> newDirs;
1455 SmallVector<Attribute> newNames;
1456 SmallVector<Attribute> newPortAnno;
1458 cast<FModuleLike>(op.getReferencedOperation(symTbl)));
1460 endFields.push_back(0);
1461 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
1462 auto srcType = type_cast<FIRRTLType>(op.getType(i));
1465 SmallVector<FlatBundleFieldEntry, 8> fieldTypes;
1466 if (!
peelType(srcType, fieldTypes, mode)) {
1467 newDirs.push_back(op.getPortDirection(i));
1468 newNames.push_back(op.getPortName(i));
1469 resultTypes.push_back(srcType);
1470 newPortAnno.push_back(oldPortAnno[i]);
1473 auto oldName = op.getPortNameStr(i);
1474 auto oldDir = op.getPortDirection(i);
1476 for (
const auto &field : fieldTypes) {
1477 newDirs.push_back(
direction::get((
unsigned)oldDir ^ field.isOutput));
1478 newNames.push_back(builder->getStringAttr(oldName + field.suffix));
1480 auto annos = filterAnnotations(
1481 context, dyn_cast_or_null<ArrayAttr>(oldPortAnno[i]), srcType,
1483 newPortAnno.push_back(annos);
1486 endFields.push_back(resultTypes.size());
1496 auto newInstance = builder->create<InstanceOp>(
1497 resultTypes, op.getModuleNameAttr(), op.getNameAttr(),
1499 builder->getArrayAttr(newNames), op.getAnnotations(),
1500 builder->getArrayAttr(newPortAnno), op.getLayersAttr(),
1501 op.getLowerToBindAttr(),
1506 auto attrNames = InstanceOp::getAttributeNames();
1507 DenseSet<StringRef> attrSet(attrNames.begin(), attrNames.end());
1508 SmallVector<NamedAttribute> newAttrs(newInstance->getAttrs());
1509 for (
auto i : llvm::make_filter_range(op->getAttrs(), [&](
auto namedAttr) {
1510 return !attrSet.count(namedAttr.getName());
1512 newAttrs.push_back(i);
1513 newInstance->setAttrs(newAttrs);
1515 SmallVector<Value> lowered;
1516 for (
size_t aggIndex = 0, eAgg = op.getNumResults(); aggIndex != eAgg;
1519 for (
size_t fieldIndex = endFields[aggIndex],
1520 eField = endFields[aggIndex + 1];
1521 fieldIndex < eField; ++fieldIndex)
1522 lowered.push_back(newInstance.getResult(fieldIndex));
1523 if (lowered.size() != 1 ||
1524 op.getType(aggIndex) != resultTypes[endFields[aggIndex]])
1525 processUsers(op.getResult(aggIndex), lowered);
1527 op.getResult(aggIndex).replaceAllUsesWith(lowered[0]);
1532 bool TypeLoweringVisitor::visitExpr(SubaccessOp op) {
1533 auto input = op.getInput();
1534 FVectorType vType = input.getType();
1537 if (vType.getNumElements() == 0) {
1538 Value inv = builder->create<InvalidValueOp>(vType.getElementType());
1539 op.replaceAllUsesWith(inv);
1544 if (ConstantOp arg =
1545 llvm::dyn_cast_or_null<ConstantOp>(op.getIndex().getDefiningOp())) {
1546 auto sio = builder->create<SubindexOp>(op.getInput(),
1547 arg.getValue().getExtValue());
1548 op.replaceAllUsesWith(sio.getResult());
1553 SmallVector<Value> inputs;
1554 inputs.reserve(vType.getNumElements());
1555 for (
int index = vType.getNumElements() - 1; index >= 0; index--)
1556 inputs.push_back(builder->create<SubindexOp>(input, index));
1558 Value multibitMux = builder->create<MultibitMuxOp>(op.getIndex(), inputs);
1559 op.replaceAllUsesWith(multibitMux);
1563 bool TypeLoweringVisitor::visitExpr(VectorCreateOp op) {
1564 auto clone = [&](
const FlatBundleFieldEntry &field,
1565 ArrayAttr attrs) -> Value {
1566 return op.getOperand(field.index);
1568 return lowerProducer(op, clone);
1571 bool TypeLoweringVisitor::visitExpr(BundleCreateOp op) {
1572 auto clone = [&](
const FlatBundleFieldEntry &field,
1573 ArrayAttr attrs) -> Value {
1574 return op.getOperand(field.index);
1576 return lowerProducer(op, clone);
1579 bool TypeLoweringVisitor::visitExpr(ElementwiseOrPrimOp op) {
1580 auto clone = [&](
const FlatBundleFieldEntry &field,
1581 ArrayAttr attrs) -> Value {
1582 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1583 getSubWhatever(op.getRhs(), field.index)};
1584 return type_isa<BundleType, FVectorType>(field.type)
1585 ? (Value)builder->create<ElementwiseOrPrimOp>(field.type,
1587 : (Value)builder->create<OrPrimOp>(operands);
1590 return lowerProducer(op, clone);
1593 bool TypeLoweringVisitor::visitExpr(ElementwiseAndPrimOp op) {
1594 auto clone = [&](
const FlatBundleFieldEntry &field,
1595 ArrayAttr attrs) -> Value {
1596 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1597 getSubWhatever(op.getRhs(), field.index)};
1598 return type_isa<BundleType, FVectorType>(field.type)
1599 ? (Value)builder->create<ElementwiseAndPrimOp>(field.type,
1601 : (Value)builder->create<AndPrimOp>(operands);
1604 return lowerProducer(op, clone);
1607 bool TypeLoweringVisitor::visitExpr(ElementwiseXorPrimOp op) {
1608 auto clone = [&](
const FlatBundleFieldEntry &field,
1609 ArrayAttr attrs) -> Value {
1610 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1611 getSubWhatever(op.getRhs(), field.index)};
1612 return type_isa<BundleType, FVectorType>(field.type)
1613 ? (Value)builder->create<ElementwiseXorPrimOp>(field.type,
1615 : (Value)builder->create<XorPrimOp>(operands);
1618 return lowerProducer(op, clone);
1621 bool TypeLoweringVisitor::visitExpr(MultibitMuxOp op) {
1622 auto clone = [&](
const FlatBundleFieldEntry &field,
1623 ArrayAttr attrs) -> Value {
1624 SmallVector<Value> newInputs;
1625 newInputs.reserve(op.getInputs().size());
1626 for (
auto input : op.getInputs()) {
1627 auto inputSub = getSubWhatever(input, field.index);
1628 newInputs.push_back(inputSub);
1630 return builder->create<MultibitMuxOp>(op.getIndex(), newInputs);
1632 return lowerProducer(op, clone);
1640 struct LowerTypesPass
1641 :
public circt::firrtl::impl::LowerFIRRTLTypesBase<LowerTypesPass> {
1645 preserveAggregate = preserveAggregateFlag;
1646 preserveMemories = preserveMemoriesFlag;
1648 void runOnOperation()
override;
1653 void LowerTypesPass::runOnOperation() {
1655 std::vector<FModuleLike> ops;
1657 auto &symTbl = getAnalysis<SymbolTable>();
1659 AttrCache cache(&getContext());
1661 DenseMap<FModuleLike, Convention> conventionTable;
1662 auto circuit = getOperation();
1663 for (
auto module : circuit.getOps<FModuleLike>()) {
1664 conventionTable.insert({module, module.getConvention()});
1665 ops.push_back(module);
1669 auto lowerModules = [&](FModuleLike op) -> LogicalResult {
1671 TypeLoweringVisitor(&getContext(), preserveAggregate, preserveMemories,
1672 symTbl, cache, conventionTable);
1675 return LogicalResult::failure(tl.isFailed());
1678 auto result = failableParallelForEach(&getContext(), ops, lowerModules);
1681 signalPassFailure();
1688 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.