43 #include "mlir/IR/ImplicitLocOpBuilder.h"
44 #include "mlir/IR/Threading.h"
45 #include "llvm/ADT/APSInt.h"
46 #include "llvm/ADT/BitVector.h"
47 #include "llvm/Support/Debug.h"
48 #include "llvm/Support/Parallel.h"
50 #define DEBUG_TYPE "firrtl-lower-types"
52 using namespace circt;
53 using namespace firrtl;
58 struct FlatBundleFieldEntry {
66 SmallString<16> suffix;
71 unsigned fieldID, StringRef suffix,
bool isOutput)
72 : type(type), index(index), fieldID(fieldID), suffix(suffix),
76 llvm::errs() <<
"FBFE{" << type <<
" index<" << index <<
"> fieldID<"
77 << fieldID <<
"> suffix<" << suffix <<
"> isOutput<"
78 << isOutput <<
">}\n";
83 struct PortInfoWithIP {
85 std::optional<InternalPathAttr> internalPath;
92 return mapBaseType(type, [&](
auto) {
return fieldType; });
97 auto ftype = type_dyn_cast<FIRRTLType>(type);
107 .
Case<BundleType>([&](
auto bundle) {
108 for (
size_t i = 0, e = bundle.getNumElements(); i < e; ++i) {
109 auto elt = bundle.getElement(i);
113 return bundle.getNumElements() == 0;
115 .Case<FVectorType>([&](
auto vector) {
116 if (vector.getNumElements() == 0)
120 .Case<FIRRTLBaseType>([](
auto groundType) {
123 .Case<RefType>([](
auto ref) {
return hasZeroBitWidth(ref.getType()); })
124 .Default([](
auto) {
return false; });
131 .
Case<BundleType>([&](
auto bundle) {
return false; })
132 .Case<FVectorType>([&](FVectorType vector) {
134 return vector.getElementType().isGround() &&
135 vector.getNumElements() > 1;
137 .Default([](
auto groundType) {
return true; });
144 .
Case<BundleType>([&](
auto bundle) {
return true; })
145 .Case<FVectorType>([&](FVectorType vector) {
148 .Default([](
auto groundType) {
return false; });
155 if (
auto refType = type_dyn_cast<RefType>(type)) {
157 if (refType.getForceable())
168 auto firrtlType = type_dyn_cast<FIRRTLBaseType>(type);
174 if (!firrtlType.isPassive() || firrtlType.containsAnalog() ||
186 llvm_unreachable(
"unexpected mode");
192 static bool peelType(Type type, SmallVectorImpl<FlatBundleFieldEntry> &fields,
199 if (
auto refType = type_dyn_cast<RefType>(type))
200 type = refType.getType();
202 .
Case<BundleType>([&](
auto bundle) {
203 SmallString<16> tmpSuffix;
205 for (
size_t i = 0, e = bundle.getNumElements(); i < e; ++i) {
206 auto elt = bundle.getElement(i);
209 tmpSuffix.push_back(
'_');
210 tmpSuffix.append(elt.name.getValue());
211 fields.emplace_back(elt.type, i, bundle.getFieldID(i), tmpSuffix,
216 .Case<FVectorType>([&](
auto vector) {
218 for (
size_t i = 0, e = vector.getNumElements(); i != e; ++i) {
219 fields.emplace_back(vector.getElementType(), i, vector.getFieldID(i),
220 "_" + std::to_string(i),
false);
224 .Default([](
auto op) {
return false; });
230 SubaccessOp sao = llvm::dyn_cast<SubaccessOp>(op);
234 llvm::dyn_cast_or_null<ConstantOp>(sao.getIndex().getDefiningOp());
235 return arg && sao.getInput().getType().get().getNumElements() != 0;
240 SmallVector<Operation *> retval;
241 auto defOp = op->getOperand(0).getDefiningOp();
242 while (isa_and_nonnull<SubfieldOp, SubindexOp, SubaccessOp>(defOp)) {
243 retval.push_back(defOp);
244 defOp = defOp->getOperand(0).getDefiningOp();
254 FlatBundleFieldEntry field) {
255 SmallVector<Type, 8> ports;
256 SmallVector<Attribute, 8> portNames;
257 SmallVector<Attribute, 8> portLocations;
259 auto oldPorts = op.getPorts();
260 for (
size_t portIdx = 0, e = oldPorts.size(); portIdx < e; ++portIdx) {
261 auto port = oldPorts[portIdx];
263 MemOp::getTypeForPort(op.getDepth(), field.type, port.second));
264 portNames.push_back(port.first);
268 auto newMem = b->create<MemOp>(
269 ports, op.getReadLatency(), op.getWriteLatency(), op.getDepth(),
270 op.getRuw(), portNames, (op.getName() + field.suffix).str(),
271 op.getNameKind(), op.getAnnotations().getValue(),
272 op.getPortAnnotations().getValue(), op.getInnerSymAttr());
274 if (op.getInnerSym()) {
275 op.emitError(
"cannot split memory with symbol present");
279 SmallVector<Attribute> newAnnotations;
280 for (
size_t portIdx = 0, e = newMem.getNumResults(); portIdx < e; ++portIdx) {
281 auto portType = type_cast<BundleType>(newMem.getResult(portIdx).getType());
282 auto oldPortType = type_cast<BundleType>(op.getResult(portIdx).getType());
283 SmallVector<Attribute> portAnno;
284 for (
auto attr : newMem.getPortAnnotation(portIdx)) {
287 auto targetIndex = oldPortType.getIndexForFieldID(annoFieldID);
291 if (annoFieldID == oldPortType.getFieldID(targetIndex)) {
294 b->getI32IntegerAttr(portType.getFieldID(targetIndex)));
295 portAnno.push_back(anno.
getDict());
300 if (type_isa<BundleType>(oldPortType.getElement(targetIndex).type)) {
305 auto fieldID = field.fieldID + oldPortType.getFieldID(targetIndex);
306 if (annoFieldID >= fieldID &&
311 annoFieldID - fieldID + portType.getFieldID(targetIndex);
312 anno.
setMember(
"circt.fieldID", b->getI32IntegerAttr(newFieldID));
313 portAnno.push_back(anno.
getDict());
317 portAnno.push_back(attr);
319 newAnnotations.push_back(b->getArrayAttr(portAnno));
321 newMem.setAllPortAnnotations(newAnnotations);
331 AttrCache(MLIRContext *context) {
343 AttrCache(
const AttrCache &) =
default;
346 StringAttr nameAttr, nameKindAttr, sPortDirections, sPortNames, sPortTypes,
347 sPortSyms, sPortLocations, sPortAnnotations, sEmpty;
352 struct TypeLoweringVisitor :
public FIRRTLVisitor<TypeLoweringVisitor, bool> {
357 SymbolTable &symTbl,
const AttrCache &cache,
358 const llvm::DenseMap<FModuleLike, Convention> &conventionTable)
359 : context(context), aggregatePreservationMode(preserveAggregate),
360 memoryPreservationMode(memoryPreservationMode), symTbl(symTbl),
361 cache(cache), conventionTable(conventionTable) {}
368 void lowerModule(FModuleLike op);
370 bool lowerArg(FModuleLike module,
size_t argIndex,
size_t argsRemoved,
371 SmallVectorImpl<PortInfoWithIP> &newArgs,
372 SmallVectorImpl<Value> &lowering);
373 std::pair<Value, PortInfoWithIP>
374 addArg(Operation *module,
unsigned insertPt,
unsigned insertPtOffset,
375 FIRRTLType srcType,
const FlatBundleFieldEntry &field,
376 PortInfoWithIP &oldArg, hw::InnerSymAttr newSym);
379 bool visitDecl(FExtModuleOp op);
380 bool visitDecl(FModuleOp op);
381 bool visitDecl(InstanceOp op);
382 bool visitDecl(MemOp op);
383 bool visitDecl(NodeOp op);
384 bool visitDecl(RegOp op);
385 bool visitDecl(WireOp op);
386 bool visitDecl(RegResetOp op);
387 bool visitExpr(InvalidValueOp op);
388 bool visitExpr(SubaccessOp op);
389 bool visitExpr(VectorCreateOp op);
390 bool visitExpr(BundleCreateOp op);
391 bool visitExpr(ElementwiseAndPrimOp op);
392 bool visitExpr(ElementwiseOrPrimOp op);
393 bool visitExpr(ElementwiseXorPrimOp op);
394 bool visitExpr(MultibitMuxOp op);
395 bool visitExpr(MuxPrimOp op);
396 bool visitExpr(Mux2CellIntrinsicOp op);
397 bool visitExpr(Mux4CellIntrinsicOp op);
398 bool visitExpr(mlir::UnrealizedConversionCastOp op);
399 bool visitExpr(BitCastOp op);
400 bool visitExpr(RefSendOp op);
401 bool visitExpr(RefResolveOp op);
402 bool visitExpr(RefCastOp op);
403 bool visitStmt(ConnectOp op);
404 bool visitStmt(StrictConnectOp op);
405 bool visitStmt(RefDefineOp op);
406 bool visitStmt(WhenOp op);
407 bool visitStmt(GroupOp op);
409 bool isFailed()
const {
return encounteredError; }
412 void processUsers(Value val, ArrayRef<Value> mapping);
413 bool processSAPath(Operation *);
414 void lowerBlock(Block *);
415 void lowerSAWritePath(Operation *, ArrayRef<Operation *> writePath);
425 llvm::function_ref<Value(
const FlatBundleFieldEntry &, ArrayAttr)> clone,
430 ArrayAttr filterAnnotations(MLIRContext *ctxt, ArrayAttr annotations,
431 FIRRTLType srcType, FlatBundleFieldEntry field);
435 LogicalResult partitionSymbols(hw::InnerSymAttr sym,
FIRRTLType parentType,
436 SmallVectorImpl<hw::InnerSymAttr> &newSyms,
440 getPreservationModeForModule(FModuleLike moduleLike);
441 Value getSubWhatever(Value val,
size_t index);
443 size_t uniqueIdx = 0;
444 std::string uniqueName() {
445 auto myID = uniqueIdx++;
446 return (Twine(
"__GEN_") + Twine(myID)).str();
449 MLIRContext *context;
462 const AttrCache &cache;
464 const llvm::DenseMap<FModuleLike, Convention> &conventionTable;
467 bool encounteredError =
false;
474 TypeLoweringVisitor::getPreservationModeForModule(FModuleLike module) {
475 auto lookup = conventionTable.find(module);
476 if (lookup == conventionTable.end())
477 return aggregatePreservationMode;
478 switch (lookup->second) {
479 case Convention::Scalarized:
481 case Convention::Internal:
482 return aggregatePreservationMode;
484 llvm_unreachable(
"Unknown convention");
485 return aggregatePreservationMode;
488 Value TypeLoweringVisitor::getSubWhatever(Value val,
size_t index) {
489 if (type_isa<BundleType>(val.getType()))
490 return builder->create<SubfieldOp>(val, index);
491 if (type_isa<FVectorType>(val.getType()))
492 return builder->create<SubindexOp>(val, index);
493 if (type_isa<RefType>(val.getType()))
494 return builder->create<RefSubOp>(val, index);
495 llvm_unreachable(
"Unknown aggregate type");
500 bool TypeLoweringVisitor::processSAPath(Operation *op) {
503 if (writePath.empty())
506 lowerSAWritePath(op, writePath);
509 op->eraseOperands(0, 2);
511 for (
size_t i = 0; i < writePath.size(); ++i) {
512 if (writePath[i]->use_empty()) {
513 writePath[i]->erase();
521 void TypeLoweringVisitor::lowerBlock(Block *block) {
523 for (
auto it = block->rbegin(), e = block->rend(); it != e;) {
525 builder->setInsertionPoint(&iop);
527 bool removeOp = dispatchVisitor(&iop);
536 ArrayAttr TypeLoweringVisitor::filterAnnotations(MLIRContext *ctxt,
537 ArrayAttr annotations,
539 FlatBundleFieldEntry field) {
540 SmallVector<Attribute> retval;
541 if (!annotations || annotations.empty())
543 for (
auto opAttr : annotations) {
545 auto fieldID = anno.getFieldID();
546 anno.removeMember(
"circt.fieldID");
551 retval.push_back(anno.getAttr());
556 if (fieldID < field.fieldID ||
561 if (
auto newFieldID = fieldID - field.fieldID) {
564 anno.setMember(
"circt.fieldID",
builder->getI32IntegerAttr(newFieldID));
567 retval.push_back(anno.getAttr());
572 LogicalResult TypeLoweringVisitor::partitionSymbols(
574 SmallVectorImpl<hw::InnerSymAttr> &newSyms, Location errorLoc) {
577 if (!sym || sym.empty())
580 auto *context = sym.getContext();
584 return mlir::emitError(errorLoc,
585 "unable to partition symbol on unsupported type ")
588 return TypeSwitch<FIRRTLType, LogicalResult>(baseType)
589 .Case<BundleType, FVectorType>([&](
auto aggType) -> LogicalResult {
593 hw::InnerSymPropertiesAttr prop;
597 SmallVector<BinningInfo> binning;
598 for (
auto prop : sym) {
599 auto fieldID = prop.getFieldID();
602 return mlir::emitError(errorLoc,
"unable to lower due to symbol ")
604 <<
" with target not preserved by lowering";
605 auto [index, relFieldID] = aggType.getIndexAndSubfieldID(fieldID);
606 binning.push_back({index, relFieldID, prop});
610 llvm::stable_sort(binning, [&](
auto &lhs,
auto &rhs) {
611 return std::tuple(lhs.index, lhs.relFieldID) <
612 std::tuple(rhs.index, rhs.relFieldID);
617 newSyms.resize(aggType.getNumElements());
618 for (
auto binIt = binning.begin(), binEnd = binning.end();
620 auto curIndex = binIt->index;
621 SmallVector<hw::InnerSymPropertiesAttr> propsForIndex;
623 while (binIt != binEnd && binIt->index == curIndex) {
625 context, binIt->prop.getName(), binIt->relFieldID,
626 binIt->prop.getSymVisibility()));
630 assert(!newSyms[curIndex]);
635 .Default([&](
auto ty) {
636 return mlir::emitError(
637 errorLoc,
"unable to partition symbol on unsupported type ")
642 bool TypeLoweringVisitor::lowerProducer(
644 llvm::function_ref<Value(
const FlatBundleFieldEntry &, ArrayAttr)> clone,
648 srcType = op->getResult(0).getType();
649 auto srcFType = type_dyn_cast<FIRRTLType>(srcType);
652 SmallVector<FlatBundleFieldEntry, 8> fieldTypes;
654 if (!
peelType(srcFType, fieldTypes, aggregatePreservationMode))
657 SmallVector<Value> lowered;
659 SmallString<16> loweredName;
660 auto nameKindAttr = op->getAttrOfType<NameKindEnumAttr>(cache.nameKindAttr);
662 if (
auto nameAttr = op->getAttrOfType<StringAttr>(cache.nameAttr))
663 loweredName = nameAttr.getValue();
664 auto baseNameLen = loweredName.size();
665 auto oldAnno = op->getAttr(
"annotations").dyn_cast_or_null<ArrayAttr>();
667 SmallVector<hw::InnerSymAttr> fieldSyms(fieldTypes.size());
668 if (
auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(op)) {
669 if (failed(partitionSymbols(symOp.getInnerSymAttr(), srcFType, fieldSyms,
671 encounteredError =
true;
676 for (
const auto &[field, sym] : llvm::zip_equal(fieldTypes, fieldSyms)) {
677 if (!loweredName.empty()) {
678 loweredName.resize(baseNameLen);
679 loweredName += field.suffix;
684 ArrayAttr loweredAttrs =
685 filterAnnotations(context, oldAnno, srcFType, field);
686 auto newVal = clone(field, loweredAttrs);
692 auto newSymOp = newVal.getDefiningOp<hw::InnerSymbolOpInterface>();
695 "op with inner symbol lowered to op that cannot take inner symbol");
696 newSymOp.setInnerSymbolAttr(sym);
700 if (
auto *newOp = newVal.getDefiningOp()) {
701 if (!loweredName.empty())
704 newOp->setAttr(cache.nameKindAttr, nameKindAttr);
706 lowered.push_back(newVal);
709 processUsers(op->getResult(0), lowered);
713 void TypeLoweringVisitor::processUsers(Value val, ArrayRef<Value> mapping) {
714 for (
auto *user : llvm::make_early_inc_range(val.getUsers())) {
715 TypeSwitch<Operation *, void>(user)
716 .Case<SubindexOp>([mapping](SubindexOp sio) {
717 Value repl = mapping[sio.getIndex()];
718 sio.replaceAllUsesWith(repl);
721 .Case<SubfieldOp>([mapping](SubfieldOp sfo) {
723 Value repl = mapping[sfo.getFieldIndex()];
724 sfo.replaceAllUsesWith(repl);
727 .Case<RefSubOp>([mapping](RefSubOp refSub) {
728 Value repl = mapping[refSub.getIndex()];
729 refSub.replaceAllUsesWith(repl);
732 .Default([&](
auto op) {
743 ImplicitLocOpBuilder b(user->getLoc(), user);
747 assert(llvm::none_of(mapping, [](
auto v) {
748 auto fbasetype = type_dyn_cast<FIRRTLBaseType>(v.getType());
749 return !fbasetype || fbasetype.containsReference();
753 TypeSwitch<Type, Value>(val.getType())
754 .template Case<FVectorType>([&](
auto vecType) {
755 return b.createOrFold<VectorCreateOp>(vecType, mapping);
757 .
template Case<BundleType>([&](
auto bundleType) {
758 return b.createOrFold<BundleCreateOp>(bundleType, mapping);
760 .Default([&](
auto _) -> Value {
return {}; });
762 user->emitError(
"unable to reconstruct source of type ")
764 encounteredError =
true;
767 user->replaceUsesOfWith(val, input);
772 void TypeLoweringVisitor::lowerModule(FModuleLike op) {
773 if (
auto module = llvm::dyn_cast<FModuleOp>(*op))
775 else if (
auto extModule = llvm::dyn_cast<FExtModuleOp>(*op))
776 visitDecl(extModule);
782 std::pair<Value, PortInfoWithIP>
783 TypeLoweringVisitor::addArg(Operation *module,
unsigned insertPt,
785 const FlatBundleFieldEntry &field,
786 PortInfoWithIP &oldArg, hw::InnerSymAttr newSym) {
789 if (
auto mod = llvm::dyn_cast<FModuleOp>(module)) {
790 Block *body = mod.getBodyBlock();
792 newValue = body->insertArgument(insertPt, fieldType, oldArg.pi.loc);
796 auto name =
builder->getStringAttr(oldArg.pi.name.getValue() + field.suffix);
799 auto newAnnotations = filterAnnotations(
800 context, oldArg.pi.annotations.getArrayAttr(), srcType, field);
802 auto direction = (
Direction)((
unsigned)oldArg.pi.direction ^ field.isOutput);
804 return std::make_pair(
806 PortInfoWithIP{
PortInfo{name, fieldType, direction, newSym, oldArg.pi.loc,
808 oldArg.internalPath});
812 bool TypeLoweringVisitor::lowerArg(FModuleLike module,
size_t argIndex,
814 SmallVectorImpl<PortInfoWithIP> &newArgs,
815 SmallVectorImpl<Value> &lowering) {
818 SmallVector<FlatBundleFieldEntry> fieldTypes;
819 auto srcType = type_cast<FIRRTLType>(newArgs[argIndex].pi.type);
820 if (!
peelType(srcType, fieldTypes, getPreservationModeForModule(module)))
824 if (
auto ip = newArgs[argIndex].internalPath; ip && ip->getPath()) {
825 ::mlir::emitError(newArgs[argIndex].pi.loc,
826 "cannot lower port with internal path");
827 encounteredError =
true;
831 SmallVector<hw::InnerSymAttr> fieldSyms(fieldTypes.size());
832 if (failed(partitionSymbols(newArgs[argIndex].pi.sym, srcType, fieldSyms,
833 newArgs[argIndex].pi.loc))) {
834 encounteredError =
true;
838 for (
const auto &[idx, field, fieldSym] :
839 llvm::enumerate(fieldTypes, fieldSyms)) {
840 auto newValue = addArg(module, 1 + argIndex + idx, argsRemoved, srcType,
841 field, newArgs[argIndex], fieldSym);
842 newArgs.insert(newArgs.begin() + 1 + argIndex + idx, newValue.second);
844 lowering.push_back(newValue.first);
851 if (
auto rop = llvm::dyn_cast<SubfieldOp>(op))
852 return builder->create<SubfieldOp>(rhs, rop.getFieldIndex());
853 if (
auto rop = llvm::dyn_cast<SubindexOp>(op))
854 return builder->create<SubindexOp>(rhs, rop.getIndex());
855 if (
auto rop = llvm::dyn_cast<SubaccessOp>(op))
856 return builder->create<SubaccessOp>(rhs, rop.getIndex());
857 op->emitError(
"Unknown accessor");
861 void TypeLoweringVisitor::lowerSAWritePath(Operation *op,
862 ArrayRef<Operation *> writePath) {
863 SubaccessOp sao = cast<SubaccessOp>(writePath.back());
864 FVectorType saoType = sao.getInput().getType();
865 auto selectWidth = llvm::Log2_64_Ceil(saoType.getNumElements());
867 for (
size_t index = 0, e = saoType.getNumElements(); index < e; ++index) {
868 auto cond =
builder->create<EQPrimOp>(
871 APInt(selectWidth, index)));
872 builder->create<WhenOp>(cond,
false, [&]() {
874 Value leaf =
builder->create<SubindexOp>(sao.getInput(), index);
875 for (
int i = writePath.size() - 2; i >= 0; --i) {
879 encounteredError =
true;
890 bool TypeLoweringVisitor::visitStmt(ConnectOp op) {
891 if (processSAPath(op))
895 SmallVector<FlatBundleFieldEntry> fields;
902 for (
const auto &field : llvm::enumerate(fields)) {
903 Value src = getSubWhatever(op.getSrc(), field.index());
904 Value dest = getSubWhatever(op.getDest(), field.index());
905 if (field.value().isOutput)
906 std::swap(src, dest);
913 bool TypeLoweringVisitor::visitStmt(StrictConnectOp op) {
914 if (processSAPath(op))
918 SmallVector<FlatBundleFieldEntry> fields;
925 for (
const auto &field : llvm::enumerate(fields)) {
926 Value src = getSubWhatever(op.getSrc(), field.index());
927 Value dest = getSubWhatever(op.getDest(), field.index());
928 if (field.value().isOutput)
929 std::swap(src, dest);
930 builder->create<StrictConnectOp>(dest, src);
936 bool TypeLoweringVisitor::visitStmt(RefDefineOp op) {
938 SmallVector<FlatBundleFieldEntry> fields;
940 if (!
peelType(op.getDest().getType(), fields, aggregatePreservationMode))
944 for (
const auto &field : llvm::enumerate(fields)) {
945 Value src = getSubWhatever(op.getSrc(), field.index());
946 Value dest = getSubWhatever(op.getDest(), field.index());
947 assert(!field.value().isOutput &&
"unexpected flip in reftype destination");
948 builder->create<RefDefineOp>(dest, src);
953 bool TypeLoweringVisitor::visitStmt(WhenOp op) {
959 lowerBlock(&op.getThenBlock());
962 if (op.hasElseRegion())
963 lowerBlock(&op.getElseBlock());
968 bool TypeLoweringVisitor::visitStmt(GroupOp op) {
969 lowerBlock(op.getBody());
975 bool TypeLoweringVisitor::visitDecl(MemOp op) {
977 SmallVector<FlatBundleFieldEntry> fields;
980 if (!
peelType(op.getDataType(), fields, memoryPreservationMode))
983 if (op.getInnerSym()) {
984 op->emitError() <<
"has a symbol, but no symbols may exist on aggregates "
985 "passed through LowerTypes";
986 encounteredError =
true;
990 SmallVector<MemOp> newMemories;
991 SmallVector<WireOp> oldPorts;
994 for (
unsigned int index = 0, end = op.getNumResults(); index < end; ++index) {
995 auto result = op.getResult(index);
996 if (op.getPortKind(index) == MemOp::PortKind::Debug) {
997 op.emitOpError(
"cannot lower memory with debug port");
998 encounteredError =
true;
1001 auto wire =
builder->create<WireOp>(
1003 (op.getName() +
"_" + op.getPortName(index).getValue()).str());
1004 oldPorts.push_back(wire);
1005 result.replaceAllUsesWith(wire.getResult());
1012 for (
const auto &field : fields) {
1014 if (!newMemForField) {
1015 op.emitError(
"failed cloning memory for field");
1016 encounteredError =
true;
1019 newMemories.push_back(newMemForField);
1022 for (
size_t index = 0, rend = op.getNumResults(); index < rend; ++index) {
1023 auto result = oldPorts[index].getResult();
1024 auto rType = type_cast<BundleType>(result.getType());
1025 for (
size_t fieldIndex = 0, fend = rType.getNumElements();
1026 fieldIndex != fend; ++fieldIndex) {
1027 auto name = rType.getElement(fieldIndex).name.getValue();
1028 auto oldField =
builder->create<SubfieldOp>(result, fieldIndex);
1031 if (name ==
"data" || name ==
"mask" || name ==
"wdata" ||
1032 name ==
"wmask" || name ==
"rdata") {
1033 for (
const auto &field : fields) {
1034 auto realOldField = getSubWhatever(oldField, field.index);
1035 auto newField = getSubWhatever(
1036 newMemories[field.index].getResult(index), fieldIndex);
1037 if (rType.getElement(fieldIndex).isFlip)
1038 std::swap(realOldField, newField);
1042 for (
auto mem : newMemories) {
1044 builder->create<SubfieldOp>(mem.getResult(index), fieldIndex);
1053 bool TypeLoweringVisitor::visitDecl(FExtModuleOp extModule) {
1054 ImplicitLocOpBuilder theBuilder(extModule.getLoc(), context);
1060 auto internalPaths = extModule.getInternalPaths();
1063 SmallVector<unsigned> argsToRemove;
1064 SmallVector<PortInfoWithIP> newArgs;
1065 for (
auto [idx, pi] : llvm::enumerate(extModule.getPorts())) {
1066 std::optional<InternalPathAttr> internalPath;
1068 internalPath = cast<InternalPathAttr>(internalPaths->getValue()[idx]);
1069 newArgs.push_back({pi, internalPath});
1072 for (
size_t argIndex = 0, argsRemoved = 0; argIndex < newArgs.size();
1074 SmallVector<Value> lowering;
1075 if (lowerArg(extModule, argIndex, argsRemoved, newArgs, lowering)) {
1076 argsToRemove.push_back(argIndex);
1083 for (
auto toRemove : llvm::reverse(argsToRemove))
1084 newArgs.erase(newArgs.begin() + toRemove);
1086 SmallVector<NamedAttribute, 8> newModuleAttrs;
1089 for (
auto attr : extModule->getAttrDictionary())
1092 if (attr.getName() !=
"portDirections" && attr.getName() !=
"portNames" &&
1093 attr.getName() !=
"portTypes" && attr.getName() !=
"portAnnotations" &&
1094 attr.getName() !=
"portSyms" && attr.getName() !=
"portLocations")
1095 newModuleAttrs.push_back(attr);
1097 SmallVector<Direction> newArgDirections;
1098 SmallVector<Attribute> newArgNames;
1099 SmallVector<Attribute, 8> newArgTypes;
1100 SmallVector<Attribute, 8> newArgSyms;
1101 SmallVector<Attribute, 8> newArgLocations;
1102 SmallVector<Attribute, 8> newArgAnnotations;
1103 SmallVector<Attribute, 8> newInternalPaths;
1106 for (
auto &port : newArgs) {
1107 newArgDirections.push_back(port.pi.direction);
1108 newArgNames.push_back(port.pi.name);
1110 newArgSyms.push_back(port.pi.sym);
1111 newArgLocations.push_back(port.pi.loc);
1112 newArgAnnotations.push_back(port.pi.annotations.getArrayAttr());
1114 newInternalPaths.push_back(port.internalPath.value_or(emptyInternalPath));
1117 newModuleAttrs.push_back(
1118 NamedAttribute(cache.sPortDirections,
1121 newModuleAttrs.push_back(
1122 NamedAttribute(cache.sPortNames,
builder.getArrayAttr(newArgNames)));
1124 newModuleAttrs.push_back(
1125 NamedAttribute(cache.sPortTypes,
builder.getArrayAttr(newArgTypes)));
1127 newModuleAttrs.push_back(NamedAttribute(
1128 cache.sPortLocations,
builder.getArrayAttr(newArgLocations)));
1130 newModuleAttrs.push_back(NamedAttribute(
1131 cache.sPortAnnotations,
builder.getArrayAttr(newArgAnnotations)));
1134 extModule->setAttrs(newModuleAttrs);
1135 extModule.setPortSymbols(newArgSyms);
1137 extModule.setInternalPathsAttr(
builder.getArrayAttr(newInternalPaths));
1142 bool TypeLoweringVisitor::visitDecl(FModuleOp module) {
1143 auto *body = module.getBodyBlock();
1145 ImplicitLocOpBuilder theBuilder(module.getLoc(), context);
1152 llvm::BitVector argsToRemove;
1153 auto newArgs = llvm::map_to_vector(module.getPorts(), [](
auto pi) {
1154 return PortInfoWithIP{pi, std::nullopt};
1156 for (
size_t argIndex = 0, argsRemoved = 0; argIndex < newArgs.size();
1158 SmallVector<Value> lowerings;
1159 if (lowerArg(module, argIndex, argsRemoved, newArgs, lowerings)) {
1160 auto arg = module.getArgument(argIndex);
1161 processUsers(arg, lowerings);
1162 argsToRemove.push_back(
true);
1165 argsToRemove.push_back(
false);
1170 body->eraseArguments(argsToRemove);
1171 for (
auto deadArg = argsToRemove.find_last(); deadArg != -1;
1172 deadArg = argsToRemove.find_prev(deadArg))
1173 newArgs.erase(newArgs.begin() + deadArg);
1175 SmallVector<NamedAttribute, 8> newModuleAttrs;
1178 for (
auto attr : module->getAttrDictionary())
1181 if (attr.getName() !=
"portNames" && attr.getName() !=
"portDirections" &&
1182 attr.getName() !=
"portTypes" && attr.getName() !=
"portAnnotations" &&
1183 attr.getName() !=
"portSyms" && attr.getName() !=
"portLocations")
1184 newModuleAttrs.push_back(attr);
1186 SmallVector<Direction> newArgDirections;
1187 SmallVector<Attribute> newArgNames;
1188 SmallVector<Attribute> newArgTypes;
1189 SmallVector<Attribute> newArgSyms;
1190 SmallVector<Attribute> newArgLocations;
1191 SmallVector<Attribute, 8> newArgAnnotations;
1192 for (
auto &port : newArgs) {
1193 newArgDirections.push_back(port.pi.direction);
1194 newArgNames.push_back(port.pi.name);
1196 newArgSyms.push_back(port.pi.sym);
1197 newArgLocations.push_back(port.pi.loc);
1198 newArgAnnotations.push_back(port.pi.annotations.getArrayAttr());
1201 newModuleAttrs.push_back(
1202 NamedAttribute(cache.sPortDirections,
1205 newModuleAttrs.push_back(
1206 NamedAttribute(cache.sPortNames,
builder->getArrayAttr(newArgNames)));
1208 newModuleAttrs.push_back(
1209 NamedAttribute(cache.sPortTypes,
builder->getArrayAttr(newArgTypes)));
1211 newModuleAttrs.push_back(NamedAttribute(
1212 cache.sPortLocations,
builder->getArrayAttr(newArgLocations)));
1214 newModuleAttrs.push_back(NamedAttribute(
1215 cache.sPortAnnotations,
builder->getArrayAttr(newArgAnnotations)));
1218 module->setAttrs(newModuleAttrs);
1219 module.setPortSymbols(newArgSyms);
1224 bool TypeLoweringVisitor::visitDecl(WireOp op) {
1225 if (op.isForceable())
1228 auto clone = [&](
const FlatBundleFieldEntry &field,
1229 ArrayAttr attrs) -> Value {
1231 ->create<WireOp>(
mapLoweredType(op.getDataRaw().getType(), field.type),
1232 "", NameKindEnum::DroppableName, attrs, StringAttr{})
1235 return lowerProducer(op, clone);
1239 bool TypeLoweringVisitor::visitDecl(RegOp op) {
1240 if (op.isForceable())
1243 auto clone = [&](
const FlatBundleFieldEntry &field,
1244 ArrayAttr attrs) -> Value {
1246 ->create<RegOp>(field.type, op.getClockVal(),
"",
1247 NameKindEnum::DroppableName, attrs, StringAttr{})
1250 return lowerProducer(op, clone);
1254 bool TypeLoweringVisitor::visitDecl(RegResetOp op) {
1255 if (op.isForceable())
1258 auto clone = [&](
const FlatBundleFieldEntry &field,
1259 ArrayAttr attrs) -> Value {
1260 auto resetVal = getSubWhatever(op.getResetValue(), field.index);
1262 ->create<RegResetOp>(field.type, op.getClockVal(), op.getResetSignal(),
1263 resetVal,
"", NameKindEnum::DroppableName, attrs,
1267 return lowerProducer(op, clone);
1271 bool TypeLoweringVisitor::visitDecl(NodeOp op) {
1272 if (op.isForceable())
1275 auto clone = [&](
const FlatBundleFieldEntry &field,
1276 ArrayAttr attrs) -> Value {
1277 auto input = getSubWhatever(op.getInput(), field.index);
1279 ->create<NodeOp>(input,
"", NameKindEnum::DroppableName, attrs)
1282 return lowerProducer(op, clone);
1286 bool TypeLoweringVisitor::visitExpr(InvalidValueOp op) {
1287 auto clone = [&](
const FlatBundleFieldEntry &field,
1288 ArrayAttr attrs) -> Value {
1289 return builder->create<InvalidValueOp>(field.type);
1291 return lowerProducer(op, clone);
1295 bool TypeLoweringVisitor::visitExpr(MuxPrimOp op) {
1296 auto clone = [&](
const FlatBundleFieldEntry &field,
1297 ArrayAttr attrs) -> Value {
1298 auto high = getSubWhatever(op.getHigh(), field.index);
1299 auto low = getSubWhatever(op.getLow(), field.index);
1300 return builder->create<MuxPrimOp>(op.getSel(), high, low);
1302 return lowerProducer(op, clone);
1306 bool TypeLoweringVisitor::visitExpr(Mux2CellIntrinsicOp op) {
1307 auto clone = [&](
const FlatBundleFieldEntry &field,
1308 ArrayAttr attrs) -> Value {
1309 auto high = getSubWhatever(op.getHigh(), field.index);
1310 auto low = getSubWhatever(op.getLow(), field.index);
1311 return builder->create<Mux2CellIntrinsicOp>(op.getSel(), high, low);
1313 return lowerProducer(op, clone);
1317 bool TypeLoweringVisitor::visitExpr(Mux4CellIntrinsicOp op) {
1318 auto clone = [&](
const FlatBundleFieldEntry &field,
1319 ArrayAttr attrs) -> Value {
1320 auto v3 = getSubWhatever(op.getV3(), field.index);
1321 auto v2 = getSubWhatever(op.getV2(), field.index);
1322 auto v1 = getSubWhatever(op.getV1(), field.index);
1323 auto v0 = getSubWhatever(op.getV0(), field.index);
1324 return builder->create<Mux4CellIntrinsicOp>(op.getSel(), v3, v2, v1, v0);
1326 return lowerProducer(op, clone);
1330 bool TypeLoweringVisitor::visitExpr(mlir::UnrealizedConversionCastOp op) {
1331 auto clone = [&](
const FlatBundleFieldEntry &field,
1332 ArrayAttr attrs) -> Value {
1333 auto input = getSubWhatever(op.getOperand(0), field.index);
1334 return builder->create<mlir::UnrealizedConversionCastOp>(field.type, input)
1337 return lowerProducer(op, clone);
1341 bool TypeLoweringVisitor::visitExpr(BitCastOp op) {
1342 Value srcLoweredVal = op.getInput();
1346 SmallVector<FlatBundleFieldEntry> fields;
1347 if (
peelType(op.getInput().getType(), fields, PreserveAggregate::None)) {
1348 size_t uptoBits = 0;
1351 for (
const auto &field : llvm::enumerate(fields)) {
1352 auto fieldBitwidth = *
getBitWidth(field.value().type);
1354 if (fieldBitwidth == 0)
1356 Value src = getSubWhatever(op.getInput(), field.index());
1358 src =
builder->createOrFold<BitCastOp>(
1362 srcLoweredVal = src;
1364 srcLoweredVal =
builder->create<CatPrimOp>(src, srcLoweredVal);
1366 uptoBits += fieldBitwidth;
1369 srcLoweredVal =
builder->createOrFold<AsUIntPrimOp>(srcLoweredVal);
1373 if (type_isa<BundleType, FVectorType>(op.getResult().getType())) {
1375 size_t uptoBits = 0;
1376 auto clone = [&](
const FlatBundleFieldEntry &field,
1377 ArrayAttr attrs) -> Value {
1383 return builder->create<InvalidValueOp>(field.type);
1388 srcLoweredVal, uptoBits + fieldBits - 1, uptoBits);
1389 uptoBits += fieldBits;
1392 return lowerProducer(op, clone);
1396 if (type_isa<SIntType>(op.getType()))
1397 srcLoweredVal =
builder->create<AsSIntPrimOp>(srcLoweredVal);
1398 op.getResult().replaceAllUsesWith(srcLoweredVal);
1402 bool TypeLoweringVisitor::visitExpr(RefSendOp op) {
1403 auto clone = [&](
const FlatBundleFieldEntry &field,
1404 ArrayAttr attrs) -> Value {
1405 return builder->create<RefSendOp>(
1406 getSubWhatever(op.getBase(), field.index));
1411 return lowerProducer(op, clone);
1414 bool TypeLoweringVisitor::visitExpr(RefResolveOp op) {
1415 auto clone = [&](
const FlatBundleFieldEntry &field,
1416 ArrayAttr attrs) -> Value {
1417 Value src = getSubWhatever(op.getRef(), field.index);
1418 return builder->create<RefResolveOp>(src);
1422 return lowerProducer(op, clone, op.getRef().getType());
1425 bool TypeLoweringVisitor::visitExpr(RefCastOp op) {
1426 auto clone = [&](
const FlatBundleFieldEntry &field,
1427 ArrayAttr attrs) -> Value {
1428 auto input = getSubWhatever(op.getInput(), field.index);
1431 return lowerProducer(op, clone);
1434 bool TypeLoweringVisitor::visitDecl(InstanceOp op) {
1436 SmallVector<Type, 8> resultTypes;
1437 SmallVector<int64_t, 8> endFields;
1438 auto oldPortAnno = op.getPortAnnotations();
1439 SmallVector<Direction> newDirs;
1440 SmallVector<Attribute> newNames;
1441 SmallVector<Attribute> newPortAnno;
1443 cast<FModuleLike>(op.getReferencedModule(symTbl)));
1445 endFields.push_back(0);
1446 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
1447 auto srcType = type_cast<FIRRTLType>(op.getType(i));
1450 SmallVector<FlatBundleFieldEntry, 8> fieldTypes;
1451 if (!
peelType(srcType, fieldTypes, mode)) {
1452 newDirs.push_back(op.getPortDirection(i));
1453 newNames.push_back(op.getPortName(i));
1454 resultTypes.push_back(srcType);
1455 newPortAnno.push_back(oldPortAnno[i]);
1458 auto oldName = op.getPortNameStr(i);
1459 auto oldDir = op.getPortDirection(i);
1461 for (
const auto &field : fieldTypes) {
1462 newDirs.push_back(
direction::get((
unsigned)oldDir ^ field.isOutput));
1463 newNames.push_back(
builder->getStringAttr(oldName + field.suffix));
1465 auto annos = filterAnnotations(
1466 context, oldPortAnno[i].dyn_cast_or_null<ArrayAttr>(), srcType,
1468 newPortAnno.push_back(annos);
1471 endFields.push_back(resultTypes.size());
1481 auto newInstance =
builder->create<InstanceOp>(
1482 resultTypes, op.getModuleNameAttr(), op.getNameAttr(),
1484 builder->getArrayAttr(newNames), op.getAnnotations(),
1485 builder->getArrayAttr(newPortAnno), op.getLowerToBindAttr(),
1490 auto attrNames = InstanceOp::getAttributeNames();
1491 DenseSet<StringRef> attrSet(attrNames.begin(), attrNames.end());
1492 SmallVector<NamedAttribute> newAttrs(newInstance->getAttrs());
1493 for (
auto i : llvm::make_filter_range(op->getAttrs(), [&](
auto namedAttr) {
1494 return !attrSet.count(namedAttr.getName());
1496 newAttrs.push_back(i);
1497 newInstance->setAttrs(newAttrs);
1499 SmallVector<Value> lowered;
1500 for (
size_t aggIndex = 0, eAgg = op.getNumResults(); aggIndex != eAgg;
1503 for (
size_t fieldIndex = endFields[aggIndex],
1504 eField = endFields[aggIndex + 1];
1505 fieldIndex < eField; ++fieldIndex)
1506 lowered.push_back(newInstance.getResult(fieldIndex));
1507 if (lowered.size() != 1 ||
1508 op.getType(aggIndex) != resultTypes[endFields[aggIndex]])
1509 processUsers(op.getResult(aggIndex), lowered);
1511 op.getResult(aggIndex).replaceAllUsesWith(lowered[0]);
1516 bool TypeLoweringVisitor::visitExpr(SubaccessOp op) {
1517 auto input = op.getInput();
1518 FVectorType vType = input.getType();
1521 if (vType.getNumElements() == 0) {
1522 Value inv =
builder->create<InvalidValueOp>(vType.getElementType());
1523 op.replaceAllUsesWith(inv);
1528 if (ConstantOp arg =
1529 llvm::dyn_cast_or_null<ConstantOp>(op.getIndex().getDefiningOp())) {
1530 auto sio =
builder->create<SubindexOp>(op.getInput(),
1531 arg.getValue().getExtValue());
1532 op.replaceAllUsesWith(sio.getResult());
1537 SmallVector<Value>
inputs;
1538 inputs.reserve(vType.getNumElements());
1539 for (
int index = vType.getNumElements() - 1; index >= 0; index--)
1540 inputs.push_back(
builder->create<SubindexOp>(input, index));
1542 Value multibitMux =
builder->create<MultibitMuxOp>(op.getIndex(),
inputs);
1543 op.replaceAllUsesWith(multibitMux);
1547 bool TypeLoweringVisitor::visitExpr(VectorCreateOp op) {
1548 auto clone = [&](
const FlatBundleFieldEntry &field,
1549 ArrayAttr attrs) -> Value {
1550 return op.getOperand(field.index);
1552 return lowerProducer(op, clone);
1555 bool TypeLoweringVisitor::visitExpr(BundleCreateOp op) {
1556 auto clone = [&](
const FlatBundleFieldEntry &field,
1557 ArrayAttr attrs) -> Value {
1558 return op.getOperand(field.index);
1560 return lowerProducer(op, clone);
1563 bool TypeLoweringVisitor::visitExpr(ElementwiseOrPrimOp op) {
1564 auto clone = [&](
const FlatBundleFieldEntry &field,
1565 ArrayAttr attrs) -> Value {
1566 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1567 getSubWhatever(op.getRhs(), field.index)};
1568 return type_isa<BundleType, FVectorType>(field.type)
1569 ? (Value)
builder->create<ElementwiseOrPrimOp>(field.type,
1571 : (Value)
builder->create<OrPrimOp>(operands);
1574 return lowerProducer(op, clone);
1577 bool TypeLoweringVisitor::visitExpr(ElementwiseAndPrimOp op) {
1578 auto clone = [&](
const FlatBundleFieldEntry &field,
1579 ArrayAttr attrs) -> Value {
1580 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1581 getSubWhatever(op.getRhs(), field.index)};
1582 return type_isa<BundleType, FVectorType>(field.type)
1583 ? (Value)
builder->create<ElementwiseAndPrimOp>(field.type,
1585 : (Value)
builder->create<AndPrimOp>(operands);
1588 return lowerProducer(op, clone);
1591 bool TypeLoweringVisitor::visitExpr(ElementwiseXorPrimOp op) {
1592 auto clone = [&](
const FlatBundleFieldEntry &field,
1593 ArrayAttr attrs) -> Value {
1594 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1595 getSubWhatever(op.getRhs(), field.index)};
1596 return type_isa<BundleType, FVectorType>(field.type)
1597 ? (Value)
builder->create<ElementwiseXorPrimOp>(field.type,
1599 : (Value)
builder->create<XorPrimOp>(operands);
1602 return lowerProducer(op, clone);
1605 bool TypeLoweringVisitor::visitExpr(MultibitMuxOp op) {
1606 auto clone = [&](
const FlatBundleFieldEntry &field,
1607 ArrayAttr attrs) -> Value {
1608 SmallVector<Value> newInputs;
1609 newInputs.reserve(op.getInputs().size());
1610 for (
auto input : op.getInputs()) {
1611 auto inputSub = getSubWhatever(input, field.index);
1612 newInputs.push_back(inputSub);
1614 return builder->create<MultibitMuxOp>(op.getIndex(), newInputs);
1616 return lowerProducer(op, clone);
1624 struct LowerTypesPass :
public LowerFIRRTLTypesBase<LowerTypesPass> {
1628 preserveAggregate = preserveAggregateFlag;
1629 preserveMemories = preserveMemoriesFlag;
1631 void runOnOperation()
override;
1636 void LowerTypesPass::runOnOperation() {
1638 llvm::dbgs() <<
"===- Running LowerTypes Pass "
1639 "------------------------------------------------===\n");
1640 std::vector<FModuleLike> ops;
1642 auto &symTbl = getAnalysis<SymbolTable>();
1644 AttrCache cache(&getContext());
1646 DenseMap<FModuleLike, Convention> conventionTable;
1647 auto circuit = getOperation();
1648 for (
auto module : circuit.getOps<FModuleLike>()) {
1649 conventionTable.insert({module, module.getConvention()});
1650 ops.push_back(module);
1654 auto lowerModules = [&](FModuleLike op) -> LogicalResult {
1656 TypeLoweringVisitor(&getContext(), preserveAggregate, preserveMemories,
1657 symTbl, cache, conventionTable);
1660 return LogicalResult::failure(tl.isFailed());
1663 auto result = failableParallelForEach(&getContext(), ops, lowerModules);
1666 signalPassFailure();
1673 return std::make_unique<LowerTypesPass>(mode, memoryMode);
assert(baseType &&"element must be base type")
static void dump(DIVariable &variable, raw_indented_ostream &os)
static Value extractBits(OpBuilder &builder, Location loc, Value value, unsigned startBit, unsigned bitWidth)
static bool hasZeroBitWidth(FIRRTLType type)
Return true if the type has more than zero bitwidth.
static bool isPreservableAggregateType(Type type, PreserveAggregate::PreserveMode mode)
Return true if we can preserve the type.
static SmallVector< Operation * > getSAWritePath(Operation *op)
Look through and collect subfields leading to a subaccess.
static FIRRTLType mapLoweredType(FIRRTLType type, FIRRTLBaseType fieldType)
Return fieldType or fieldType as same ref as type.
static MemOp cloneMemWithNewType(ImplicitLocOpBuilder *b, MemOp op, FlatBundleFieldEntry field)
Clone memory for the specified field. Returns null op on error.
static bool containsBundleType(FIRRTLType type)
Return true if the type has a bundle type as subtype.
static Value cloneAccess(ImplicitLocOpBuilder *builder, Operation *op, Value rhs)
static bool peelType(Type type, SmallVectorImpl< FlatBundleFieldEntry > &fields, PreserveAggregate::PreserveMode mode)
Peel one layer of an aggregate type into its components.
static bool isNotSubAccess(Operation *op)
Return if something is not a normal subaccess.
static bool isOneDimVectorType(FIRRTLType type)
Return true if the type is a 1d vector type or ground type.
llvm::SmallVector< StringAttr > inputs
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
This class provides a read-only projection of an annotation.
DictionaryAttr getDict() const
Get the data dictionary of this attribute.
unsigned getFieldID() const
Get the field id this attribute targets.
void setMember(StringAttr name, Attribute value)
Add or set a member of the annotation to a value.
This class implements the same functionality as TypeSwitch except that it uses firrtl::type_dyn_cast ...
FIRRTLTypeSwitch< T, ResultT > & Case(CallableT &&caseFn)
Add a case on the given type.
FIRRTLVisitor allows you to visit all of the expr/stmt/decls with one class declaration.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
IntegerAttr packAttribute(MLIRContext *context, size_t nIns, size_t nOuts)
Returns an IntegerAttr containing the packed representation of the direction counts.
@ All
Preserve all aggregate values.
@ OneDimVec
Preserve only 1d vectors of ground type (e.g. UInt<2>[3]).
@ Vec
Preserve only vectors (e.g. UInt<2>[3][3]).
@ None
Don't preserve aggregate at all.
IntegerAttr packAttribute(MLIRContext *context, ArrayRef< Direction > directions)
Return a IntegerAttr 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.
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)
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
mlir::raw_indented_ostream & errs()
mlir::raw_indented_ostream & dbgs()
This holds the name and type that describes the module's ports.