39#include "mlir/IR/ImplicitLocOpBuilder.h"
40#include "mlir/IR/Threading.h"
41#include "mlir/Pass/Pass.h"
42#include "llvm/ADT/APSInt.h"
43#include "llvm/ADT/BitVector.h"
44#include "llvm/Support/Debug.h"
46#define DEBUG_TYPE "firrtl-lower-types"
50#define GEN_PASS_DEF_LOWERFIRRTLTYPES
51#include "circt/Dialect/FIRRTL/Passes.h.inc"
56using namespace firrtl;
61struct FlatBundleFieldEntry {
69 SmallString<16> suffix;
74 unsigned fieldID, StringRef suffix,
bool isOutput)
75 : type(type), index(index), fieldID(fieldID), suffix(suffix),
79 llvm::errs() <<
"FBFE{" << type <<
" index<" << index <<
"> fieldID<"
80 << fieldID <<
"> suffix<" << suffix <<
"> isOutput<"
81 << isOutput <<
">}\n";
86struct PortInfoWithIP {
88 std::optional<InternalPathAttr> internalPath;
95 return mapBaseType(type, [&](
auto) {
return fieldType; });
100 auto ftype = type_dyn_cast<FIRRTLType>(type);
109 .
Case<BundleType>([&](
auto bundle) {
return false; })
110 .Case<FVectorType>([&](FVectorType vector) {
112 return vector.getElementType().isGround() &&
113 vector.getNumElements() > 1;
115 .Default([](
auto groundType) {
return true; });
122 .
Case<BundleType>([&](
auto bundle) {
return true; })
123 .Case<FVectorType>([&](FVectorType vector) {
126 .Default([](
auto groundType) {
return false; });
133 if (
auto refType = type_dyn_cast<RefType>(type)) {
135 if (refType.getForceable())
146 auto firrtlType = type_dyn_cast<FIRRTLBaseType>(type);
152 if (!firrtlType.isPassive() || firrtlType.containsAnalog() ||
164 llvm_unreachable(
"unexpected mode");
170static bool peelType(Type type, SmallVectorImpl<FlatBundleFieldEntry> &fields,
177 if (
auto refType = type_dyn_cast<RefType>(type))
178 type = refType.getType();
180 .
Case<BundleType>([&](
auto bundle) {
181 SmallString<16> tmpSuffix;
183 for (
size_t i = 0, e = bundle.getNumElements(); i < e; ++i) {
184 auto elt = bundle.getElement(i);
187 tmpSuffix.push_back(
'_');
188 tmpSuffix.append(elt.name.getValue());
189 fields.emplace_back(elt.type, i, bundle.getFieldID(i), tmpSuffix,
194 .Case<FVectorType>([&](
auto vector) {
196 for (
size_t i = 0, e = vector.getNumElements(); i != e; ++i) {
197 fields.emplace_back(vector.getElementType(), i, vector.getFieldID(i),
198 "_" + std::to_string(i),
false);
202 .Default([](
auto op) {
return false; });
208 SubaccessOp sao = llvm::dyn_cast<SubaccessOp>(op);
212 llvm::dyn_cast_or_null<ConstantOp>(sao.getIndex().getDefiningOp());
213 return arg && sao.getInput().getType().base().getNumElements() != 0;
218 SmallVector<Operation *> retval;
219 auto defOp = op->getOperand(0).getDefiningOp();
220 while (isa_and_nonnull<SubfieldOp, SubindexOp, SubaccessOp>(defOp)) {
221 retval.push_back(defOp);
222 defOp = defOp->getOperand(0).getDefiningOp();
232 FlatBundleFieldEntry field) {
233 SmallVector<Type, 8> ports;
234 SmallVector<Attribute, 8> portNames;
235 SmallVector<Attribute, 8> portLocations;
237 auto oldPorts = op.getPorts();
238 for (
size_t portIdx = 0, e = oldPorts.size(); portIdx < e; ++portIdx) {
239 auto port = oldPorts[portIdx];
241 MemOp::getTypeForPort(op.getDepth(), field.type, port.second));
242 portNames.push_back(port.first);
246 auto newMem = b->create<MemOp>(
247 ports, op.getReadLatency(), op.getWriteLatency(), op.getDepth(),
248 op.getRuw(), b->getArrayAttr(portNames),
249 (op.getName() + field.suffix).str(), op.getNameKind(),
250 op.getAnnotations(), op.getPortAnnotations(), op.getInnerSymAttr(),
251 op.getInitAttr(), op.getPrefixAttr());
253 if (op.getInnerSym()) {
254 op.emitError(
"cannot split memory with symbol present");
258 SmallVector<Attribute> newAnnotations;
259 for (
size_t portIdx = 0, e = newMem.getNumResults(); portIdx < e; ++portIdx) {
260 auto portType = type_cast<BundleType>(newMem.getResult(portIdx).getType());
261 auto oldPortType = type_cast<BundleType>(op.getResult(portIdx).getType());
262 SmallVector<Attribute> portAnno;
263 for (
auto attr : newMem.getPortAnnotation(portIdx)) {
266 auto targetIndex = oldPortType.getIndexForFieldID(annoFieldID);
270 if (annoFieldID == oldPortType.getFieldID(targetIndex)) {
273 b->getI32IntegerAttr(portType.getFieldID(targetIndex)));
274 portAnno.push_back(anno.
getDict());
279 if (type_isa<BundleType>(oldPortType.getElement(targetIndex).type)) {
284 auto fieldID = field.fieldID + oldPortType.getFieldID(targetIndex);
285 if (annoFieldID >= fieldID &&
290 annoFieldID - fieldID + portType.getFieldID(targetIndex);
291 anno.
setMember(
"circt.fieldID", b->getI32IntegerAttr(newFieldID));
292 portAnno.push_back(anno.
getDict());
296 portAnno.push_back(attr);
298 newAnnotations.push_back(b->getArrayAttr(portAnno));
300 newMem.setAllPortAnnotations(newAnnotations);
310 AttrCache(MLIRContext *context) {
311 i64ty = IntegerType::get(context, 64);
312 nameAttr = StringAttr::get(context,
"name");
313 nameKindAttr = StringAttr::get(context,
"nameKind");
314 sPortDirections = StringAttr::get(context,
"portDirections");
315 sPortNames = StringAttr::get(context,
"portNames");
316 sPortTypes = StringAttr::get(context,
"portTypes");
317 sPortSymbols = StringAttr::get(context,
"portSymbols");
318 sPortLocations = StringAttr::get(context,
"portLocations");
319 sPortAnnotations = StringAttr::get(context,
"portAnnotations");
320 sPortDomains = StringAttr::get(context,
"domainInfo");
321 sEmpty = StringAttr::get(context,
"");
322 aEmpty = ArrayAttr::get(context, {});
324 AttrCache(
const AttrCache &) =
default;
327 StringAttr nameAttr, nameKindAttr, sPortDirections, sPortNames, sPortTypes,
328 sPortSymbols, sPortLocations, sPortAnnotations, sPortDomains, sEmpty;
334struct TypeLoweringVisitor :
public FIRRTLVisitor<TypeLoweringVisitor, bool> {
338 Convention bodyConvention,
340 SymbolTable &symTbl,
const AttrCache &cache,
341 const llvm::DenseMap<FModuleLike, Convention> &conventionTable)
342 : context(context), defaultAggregatePreservationMode(preserveAggregate),
343 memoryPreservationMode(memoryPreservationMode), symTbl(symTbl),
344 cache(cache), conventionTable(conventionTable) {
345 bodyAggregatePreservationMode = bodyConvention == Convention::Scalarized
347 : defaultAggregatePreservationMode;
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; }
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 getPreservationModeForPorts(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;
450 ImplicitLocOpBuilder *builder;
456 const AttrCache &cache;
458 const llvm::DenseMap<FModuleLike, Convention> &conventionTable;
461 bool encounteredError =
false;
468TypeLoweringVisitor::getPreservationModeForPorts(FModuleLike module) {
469 auto lookup = conventionTable.find(module);
470 if (lookup == conventionTable.end())
471 return defaultAggregatePreservationMode;
472 switch (lookup->second) {
473 case Convention::Scalarized:
475 case Convention::Internal:
476 return defaultAggregatePreservationMode;
478 llvm_unreachable(
"Unknown convention");
479 return defaultAggregatePreservationMode;
482Value TypeLoweringVisitor::getSubWhatever(Value val,
size_t index) {
483 if (type_isa<BundleType>(val.getType()))
484 return builder->create<SubfieldOp>(val, index);
485 if (type_isa<FVectorType>(val.getType()))
486 return builder->create<SubindexOp>(val, index);
487 if (type_isa<RefType>(val.getType()))
488 return builder->create<RefSubOp>(val, index);
489 llvm_unreachable(
"Unknown aggregate type");
494bool TypeLoweringVisitor::processSAPath(Operation *op) {
497 if (writePath.empty())
500 lowerSAWritePath(op, writePath);
503 op->eraseOperands(0, 2);
505 for (
size_t i = 0; i < writePath.size(); ++i) {
506 if (writePath[i]->use_empty()) {
507 writePath[i]->erase();
515void TypeLoweringVisitor::lowerBlock(Block *block) {
517 for (
auto it = block->rbegin(), e = block->rend(); it != e;) {
519 builder->setInsertionPoint(&iop);
520 builder->setLoc(iop.getLoc());
521 bool removeOp = dispatchVisitor(&iop);
530ArrayAttr TypeLoweringVisitor::filterAnnotations(MLIRContext *ctxt,
531 ArrayAttr annotations,
533 FlatBundleFieldEntry field) {
534 SmallVector<Attribute> retval;
535 if (!annotations || annotations.empty())
536 return ArrayAttr::get(ctxt, retval);
537 for (
auto opAttr : annotations) {
539 auto fieldID = anno.getFieldID();
540 anno.removeMember(
"circt.fieldID");
545 retval.push_back(anno.getAttr());
550 if (fieldID < field.fieldID ||
555 if (
auto newFieldID = fieldID - field.fieldID) {
558 anno.setMember(
"circt.fieldID", builder->getI32IntegerAttr(newFieldID));
561 retval.push_back(anno.getAttr());
563 return ArrayAttr::get(ctxt, retval);
566LogicalResult TypeLoweringVisitor::partitionSymbols(
568 SmallVectorImpl<hw::InnerSymAttr> &newSyms, Location errorLoc) {
571 if (!sym || sym.empty())
574 auto *context = sym.getContext();
578 return mlir::emitError(errorLoc,
579 "unable to partition symbol on unsupported type ")
582 return TypeSwitch<FIRRTLType, LogicalResult>(baseType)
583 .Case<BundleType, FVectorType>([&](
auto aggType) -> LogicalResult {
587 hw::InnerSymPropertiesAttr prop;
591 SmallVector<BinningInfo> binning;
592 for (
auto prop : sym) {
593 auto fieldID = prop.getFieldID();
596 return mlir::emitError(errorLoc,
"unable to lower due to symbol ")
598 <<
" with target not preserved by lowering";
599 auto [index, relFieldID] = aggType.getIndexAndSubfieldID(fieldID);
600 binning.push_back({index, relFieldID, prop});
604 llvm::stable_sort(binning, [&](
auto &lhs,
auto &rhs) {
605 return std::tuple(lhs.index, lhs.relFieldID) <
606 std::tuple(rhs.index, rhs.relFieldID);
611 newSyms.resize(aggType.getNumElements());
612 for (
auto binIt = binning.begin(), binEnd = binning.end();
614 auto curIndex = binIt->index;
615 SmallVector<hw::InnerSymPropertiesAttr> propsForIndex;
617 while (binIt != binEnd && binIt->index == curIndex) {
618 propsForIndex.push_back(hw::InnerSymPropertiesAttr::get(
619 context, binIt->prop.getName(), binIt->relFieldID,
620 binIt->prop.getSymVisibility()));
624 assert(!newSyms[curIndex]);
625 newSyms[curIndex] = hw::InnerSymAttr::get(context, propsForIndex);
629 .Default([&](
auto ty) {
630 return mlir::emitError(
631 errorLoc,
"unable to partition symbol on unsupported type ")
636bool TypeLoweringVisitor::lowerProducer(
638 llvm::function_ref<Value(
const FlatBundleFieldEntry &, ArrayAttr)> clone,
642 srcType = op->getResult(0).getType();
643 auto srcFType = type_dyn_cast<FIRRTLType>(srcType);
646 SmallVector<FlatBundleFieldEntry, 8> fieldTypes;
648 if (!
peelType(srcFType, fieldTypes, bodyAggregatePreservationMode))
651 SmallVector<Value> lowered;
653 SmallString<16> loweredName;
654 auto nameKindAttr = op->getAttrOfType<NameKindEnumAttr>(cache.nameKindAttr);
656 if (
auto nameAttr = op->getAttrOfType<StringAttr>(cache.nameAttr))
657 loweredName = nameAttr.getValue();
658 auto baseNameLen = loweredName.size();
659 auto oldAnno = dyn_cast_or_null<ArrayAttr>(op->getAttr(
"annotations"));
661 SmallVector<hw::InnerSymAttr> fieldSyms(fieldTypes.size());
662 if (
auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(op)) {
663 if (failed(partitionSymbols(symOp.getInnerSymAttr(), srcFType, fieldSyms,
665 encounteredError =
true;
670 for (
const auto &[field, sym] :
llvm::zip_equal(fieldTypes, fieldSyms)) {
671 if (!loweredName.empty()) {
672 loweredName.resize(baseNameLen);
673 loweredName += field.suffix;
678 ArrayAttr loweredAttrs =
679 filterAnnotations(context, oldAnno, srcFType, field);
680 auto newVal = clone(field, loweredAttrs);
686 auto newSymOp = newVal.getDefiningOp<hw::InnerSymbolOpInterface>();
689 "op with inner symbol lowered to op that cannot take inner symbol");
690 newSymOp.setInnerSymbolAttr(sym);
694 if (
auto *newOp = newVal.getDefiningOp()) {
695 if (!loweredName.empty())
696 newOp->setAttr(cache.nameAttr, StringAttr::get(context, loweredName));
698 newOp->setAttr(cache.nameKindAttr, nameKindAttr);
701 newOp->setDiscardableAttrs(op->getDiscardableAttrDictionary());
703 lowered.push_back(newVal);
706 processUsers(op->getResult(0), lowered);
710void TypeLoweringVisitor::processUsers(Value val, ArrayRef<Value> mapping) {
711 for (
auto *user :
llvm::make_early_inc_range(val.getUsers())) {
712 TypeSwitch<Operation *, void>(user)
713 .Case<SubindexOp>([mapping](SubindexOp sio) {
714 Value repl = mapping[sio.getIndex()];
715 sio.replaceAllUsesWith(repl);
718 .Case<SubfieldOp>([mapping](SubfieldOp sfo) {
720 Value repl = mapping[sfo.getFieldIndex()];
721 sfo.replaceAllUsesWith(repl);
724 .Case<RefSubOp>([mapping](RefSubOp refSub) {
725 Value repl = mapping[refSub.getIndex()];
726 refSub.replaceAllUsesWith(repl);
729 .Default([&](
auto op) {
740 ImplicitLocOpBuilder b(user->getLoc(), user);
744 assert(llvm::none_of(mapping, [](
auto v) {
745 auto fbasetype = type_dyn_cast<FIRRTLBaseType>(v.getType());
746 return !fbasetype || fbasetype.containsReference();
750 TypeSwitch<Type, Value>(val.getType())
751 .template Case<FVectorType>([&](
auto vecType) {
752 return b.createOrFold<VectorCreateOp>(vecType, mapping);
754 .
template Case<BundleType>([&](
auto bundleType) {
755 return b.createOrFold<BundleCreateOp>(bundleType, mapping);
757 .Default([&](
auto _) -> Value {
return {}; });
759 user->emitError(
"unable to reconstruct source of type ")
761 encounteredError =
true;
764 user->replaceUsesOfWith(val, input);
769void TypeLoweringVisitor::lowerModule(FModuleLike op) {
770 if (
auto module = llvm::dyn_cast<FModuleOp>(*op))
772 else if (
auto extModule = llvm::dyn_cast<FExtModuleOp>(*op))
773 visitDecl(extModule);
779std::pair<Value, PortInfoWithIP>
780TypeLoweringVisitor::addArg(Operation *module,
unsigned insertPt,
782 const FlatBundleFieldEntry &field,
783 PortInfoWithIP &oldArg, hw::InnerSymAttr newSym) {
786 if (
auto mod = llvm::dyn_cast<FModuleOp>(module)) {
787 Block *body = mod.getBodyBlock();
789 newValue = body->insertArgument(insertPt, fieldType, oldArg.pi.loc);
793 auto name = builder->getStringAttr(oldArg.pi.name.getValue() + field.suffix);
796 auto newAnnotations = filterAnnotations(
797 context, oldArg.pi.annotations.getArrayAttr(), srcType, field);
799 auto direction = (
Direction)((
unsigned)oldArg.pi.direction ^ field.isOutput);
801 return std::make_pair(
803 PortInfoWithIP{
PortInfo{name, fieldType, direction, newSym, oldArg.pi.loc,
805 oldArg.internalPath});
809bool TypeLoweringVisitor::lowerArg(FModuleLike module,
size_t argIndex,
811 SmallVectorImpl<PortInfoWithIP> &newArgs,
812 SmallVectorImpl<Value> &lowering) {
815 SmallVector<FlatBundleFieldEntry> fieldTypes;
816 auto srcType = type_cast<FIRRTLType>(newArgs[argIndex].pi.type);
817 if (!
peelType(srcType, fieldTypes, getPreservationModeForPorts(module)))
821 if (
auto ip = newArgs[argIndex].internalPath; ip && ip->getPath()) {
822 ::mlir::emitError(newArgs[argIndex].pi.loc,
823 "cannot lower port with internal path");
824 encounteredError =
true;
828 SmallVector<hw::InnerSymAttr> fieldSyms(fieldTypes.size());
829 if (failed(partitionSymbols(newArgs[argIndex].pi.sym, srcType, fieldSyms,
830 newArgs[argIndex].pi.loc))) {
831 encounteredError =
true;
835 for (
const auto &[idx, field, fieldSym] :
836 llvm::enumerate(fieldTypes, fieldSyms)) {
837 auto newValue = addArg(module, 1 + argIndex + idx, argsRemoved, srcType,
838 field, newArgs[argIndex], fieldSym);
839 newArgs.insert(newArgs.begin() + 1 + argIndex + idx, newValue.second);
841 lowering.push_back(newValue.first);
846static Value
cloneAccess(ImplicitLocOpBuilder *builder, Operation *op,
848 if (
auto rop = llvm::dyn_cast<SubfieldOp>(op))
849 return builder->create<SubfieldOp>(rhs, rop.getFieldIndex());
850 if (
auto rop = llvm::dyn_cast<SubindexOp>(op))
851 return builder->create<SubindexOp>(rhs, rop.getIndex());
852 if (
auto rop = llvm::dyn_cast<SubaccessOp>(op))
853 return builder->create<SubaccessOp>(rhs, rop.getIndex());
854 op->emitError(
"Unknown accessor");
858void TypeLoweringVisitor::lowerSAWritePath(Operation *op,
859 ArrayRef<Operation *> writePath) {
860 SubaccessOp sao = cast<SubaccessOp>(writePath.back());
861 FVectorType saoType = sao.getInput().getType();
862 auto selectWidth = llvm::Log2_64_Ceil(saoType.getNumElements());
864 for (
size_t index = 0, e = saoType.getNumElements(); index < e; ++index) {
865 auto cond = builder->create<EQPrimOp>(
867 builder->createOrFold<ConstantOp>(UIntType::get(context, selectWidth),
868 APInt(selectWidth, index)));
869 builder->create<WhenOp>(cond,
false, [&]() {
871 Value leaf = builder->create<SubindexOp>(sao.getInput(), index);
872 for (
int i = writePath.size() - 2; i >= 0; --i) {
873 if (
auto access =
cloneAccess(builder, writePath[i], leaf))
876 encounteredError =
true;
887bool TypeLoweringVisitor::visitStmt(ConnectOp op) {
888 if (processSAPath(op))
892 SmallVector<FlatBundleFieldEntry> fields;
899 for (
const auto &field :
llvm::enumerate(fields)) {
900 Value src = getSubWhatever(op.getSrc(), field.index());
901 Value dest = getSubWhatever(op.getDest(), field.index());
902 if (field.value().isOutput)
903 std::swap(src, dest);
910bool TypeLoweringVisitor::visitStmt(MatchingConnectOp op) {
911 if (processSAPath(op))
915 SmallVector<FlatBundleFieldEntry> fields;
922 for (
const auto &field :
llvm::enumerate(fields)) {
923 Value src = getSubWhatever(op.getSrc(), field.index());
924 Value dest = getSubWhatever(op.getDest(), field.index());
925 if (field.value().isOutput)
926 std::swap(src, dest);
927 builder->create<MatchingConnectOp>(dest, src);
933bool TypeLoweringVisitor::visitStmt(RefDefineOp op) {
935 SmallVector<FlatBundleFieldEntry> fields;
937 if (!
peelType(op.getDest().getType(), fields, bodyAggregatePreservationMode))
941 for (
const auto &field :
llvm::enumerate(fields)) {
942 Value src = getSubWhatever(op.getSrc(), field.index());
943 Value dest = getSubWhatever(op.getDest(), field.index());
944 assert(!field.value().isOutput &&
"unexpected flip in reftype destination");
945 builder->create<RefDefineOp>(dest, src);
950bool TypeLoweringVisitor::visitStmt(WhenOp op) {
956 lowerBlock(&op.getThenBlock());
959 if (op.hasElseRegion())
960 lowerBlock(&op.getElseBlock());
965bool TypeLoweringVisitor::visitStmt(LayerBlockOp op) {
966 lowerBlock(op.getBody());
972bool TypeLoweringVisitor::visitDecl(MemOp op) {
974 SmallVector<FlatBundleFieldEntry> fields;
977 if (!
peelType(op.getDataType(), fields, memoryPreservationMode))
980 if (op.getInnerSym()) {
981 op->emitError() <<
"has a symbol, but no symbols may exist on aggregates "
982 "passed through LowerTypes";
983 encounteredError =
true;
987 SmallVector<MemOp> newMemories;
988 SmallVector<WireOp> oldPorts;
991 for (
unsigned int index = 0, end = op.getNumResults(); index <
end; ++index) {
992 auto result = op.getResult(index);
993 if (op.getPortKind(index) == MemOp::PortKind::Debug) {
994 op.emitOpError(
"cannot lower memory with debug port");
995 encounteredError =
true;
998 auto wire = builder->create<WireOp>(
1000 (op.getName() +
"_" + op.getPortName(index).getValue()).str());
1001 oldPorts.push_back(wire);
1002 result.replaceAllUsesWith(wire.getResult());
1009 for (
const auto &field : fields) {
1011 if (!newMemForField) {
1012 op.emitError(
"failed cloning memory for field");
1013 encounteredError =
true;
1016 newMemories.push_back(newMemForField);
1019 for (
size_t index = 0, rend = op.getNumResults(); index < rend; ++index) {
1020 auto result = oldPorts[index].getResult();
1021 auto rType = type_cast<BundleType>(result.getType());
1022 for (
size_t fieldIndex = 0, fend = rType.getNumElements();
1023 fieldIndex != fend; ++fieldIndex) {
1024 auto name = rType.getElement(fieldIndex).name.getValue();
1025 auto oldField = builder->create<SubfieldOp>(result, fieldIndex);
1028 if (name ==
"data" || name ==
"mask" || name ==
"wdata" ||
1029 name ==
"wmask" || name ==
"rdata") {
1030 for (
const auto &field : fields) {
1031 auto realOldField = getSubWhatever(oldField, field.index);
1032 auto newField = getSubWhatever(
1033 newMemories[field.index].getResult(index), fieldIndex);
1034 if (rType.getElement(fieldIndex).isFlip)
1035 std::swap(realOldField, newField);
1039 for (
auto mem : newMemories) {
1041 builder->create<SubfieldOp>(mem.getResult(index), fieldIndex);
1050bool TypeLoweringVisitor::visitDecl(FExtModuleOp extModule) {
1051 ImplicitLocOpBuilder theBuilder(extModule.getLoc(), context);
1052 builder = &theBuilder;
1055 OpBuilder builder(context);
1057 auto internalPaths = extModule.getInternalPaths();
1060 SmallVector<unsigned> argsToRemove;
1061 SmallVector<PortInfoWithIP> newArgs;
1062 for (
auto [idx, pi] :
llvm::enumerate(extModule.getPorts())) {
1063 std::optional<InternalPathAttr> internalPath;
1065 internalPath = cast<InternalPathAttr>(internalPaths->getValue()[idx]);
1066 newArgs.push_back({pi, internalPath});
1069 for (
size_t argIndex = 0, argsRemoved = 0; argIndex < newArgs.size();
1071 SmallVector<Value> lowering;
1072 if (lowerArg(extModule, argIndex, argsRemoved, newArgs, lowering)) {
1073 argsToRemove.push_back(argIndex);
1080 for (
auto toRemove :
llvm::reverse(argsToRemove))
1081 newArgs.erase(newArgs.begin() + toRemove);
1083 SmallVector<NamedAttribute, 8> newModuleAttrs;
1086 for (
auto attr : extModule->getAttrDictionary())
1089 if (attr.
getName() !=
"portDirections" && attr.
getName() !=
"portNames" &&
1090 attr.
getName() !=
"portTypes" && attr.
getName() !=
"portAnnotations" &&
1091 attr.
getName() !=
"portSymbols" && attr.
getName() !=
"portLocations")
1092 newModuleAttrs.push_back(attr);
1094 SmallVector<Direction> newArgDirections;
1095 SmallVector<Attribute> newArgNames;
1096 SmallVector<Attribute, 8> newArgTypes;
1097 SmallVector<Attribute, 8> newArgSyms;
1098 SmallVector<Attribute, 8> newArgLocations;
1099 SmallVector<Attribute, 8> newArgAnnotations;
1100 SmallVector<Attribute, 8> newArgDomains;
1101 SmallVector<Attribute, 8> newInternalPaths;
1103 auto emptyInternalPath = InternalPathAttr::get(context);
1104 for (
auto &port : newArgs) {
1105 newArgDirections.push_back(port.pi.direction);
1106 newArgNames.push_back(port.pi.name);
1107 newArgTypes.push_back(TypeAttr::get(port.pi.type));
1108 newArgSyms.push_back(port.pi.sym);
1109 newArgLocations.push_back(port.pi.loc);
1110 newArgAnnotations.push_back(port.pi.annotations.getArrayAttr());
1111 if (
auto domains = port.pi.domains)
1112 newArgDomains.push_back(domains);
1114 newArgDomains.push_back(cache.aEmpty);
1116 newInternalPaths.push_back(port.internalPath.value_or(emptyInternalPath));
1119 newModuleAttrs.push_back(
1120 NamedAttribute(cache.sPortDirections,
1123 newModuleAttrs.push_back(
1124 NamedAttribute(cache.sPortNames, builder.getArrayAttr(newArgNames)));
1126 newModuleAttrs.push_back(
1127 NamedAttribute(cache.sPortTypes, builder.getArrayAttr(newArgTypes)));
1129 newModuleAttrs.push_back(NamedAttribute(
1130 cache.sPortLocations, builder.getArrayAttr(newArgLocations)));
1132 newModuleAttrs.push_back(NamedAttribute(
1133 cache.sPortAnnotations, builder.getArrayAttr(newArgAnnotations)));
1135 newModuleAttrs.push_back(
1136 NamedAttribute(cache.sPortDomains, builder.getArrayAttr(newArgDomains)));
1139 extModule->setAttrs(newModuleAttrs);
1140 FModuleLike::fixupPortSymsArray(newArgSyms, context);
1141 extModule.setPortSymbols(newArgSyms);
1143 extModule.setInternalPathsAttr(builder.getArrayAttr(newInternalPaths));
1148bool TypeLoweringVisitor::visitDecl(FModuleOp module) {
1149 auto *body =
module.getBodyBlock();
1151 ImplicitLocOpBuilder theBuilder(module.getLoc(), context);
1152 builder = &theBuilder;
1158 llvm::BitVector argsToRemove;
1159 auto newArgs = llvm::map_to_vector(module.getPorts(), [](
auto pi) {
1160 return PortInfoWithIP{pi, std::nullopt};
1163 size_t argsRemoved = 0;
1164 for (
size_t argIndex = 0; argIndex < newArgs.size(); ++argIndex) {
1165 SmallVector<Value> lowerings;
1166 if (lowerArg(module, argIndex, argsRemoved, newArgs, lowerings)) {
1167 auto arg =
module.getArgument(argIndex);
1168 processUsers(arg, lowerings);
1169 argsToRemove.push_back(
true);
1172 argsToRemove.push_back(
false);
1177 if (argsRemoved != 0) {
1178 body->eraseArguments(argsToRemove);
1179 size_t size = newArgs.size();
1180 for (
size_t src = 0, dst = 0; src < size; ++src) {
1181 if (argsToRemove[src])
1183 newArgs[dst] = newArgs[src];
1186 newArgs.erase(newArgs.end() - argsRemoved, newArgs.end());
1189 SmallVector<NamedAttribute, 8> newModuleAttrs;
1192 for (
auto attr : module->getAttrDictionary())
1195 if (attr.
getName() !=
"portNames" && attr.
getName() !=
"portDirections" &&
1196 attr.
getName() !=
"portTypes" && attr.
getName() !=
"portAnnotations" &&
1197 attr.
getName() !=
"portSymbols" && attr.
getName() !=
"portLocations")
1198 newModuleAttrs.push_back(attr);
1200 SmallVector<Direction> newArgDirections;
1201 SmallVector<Attribute> newArgNames;
1202 SmallVector<Attribute> newArgTypes;
1203 SmallVector<Attribute> newArgSyms;
1204 SmallVector<Attribute> newArgLocations;
1205 SmallVector<Attribute, 8> newArgAnnotations;
1206 SmallVector<Attribute> newPortDomains;
1207 for (
auto &port : newArgs) {
1208 newArgDirections.push_back(port.pi.direction);
1209 newArgNames.push_back(port.pi.name);
1210 newArgTypes.push_back(TypeAttr::get(port.pi.type));
1211 newArgSyms.push_back(port.pi.sym);
1212 newArgLocations.push_back(port.pi.loc);
1213 newArgAnnotations.push_back(port.pi.annotations.getArrayAttr());
1214 if (
auto domains = port.pi.domains)
1215 newPortDomains.push_back(domains);
1217 newPortDomains.push_back(cache.aEmpty);
1220 newModuleAttrs.push_back(
1221 NamedAttribute(cache.sPortDirections,
1224 newModuleAttrs.push_back(
1225 NamedAttribute(cache.sPortNames, builder->getArrayAttr(newArgNames)));
1227 newModuleAttrs.push_back(
1228 NamedAttribute(cache.sPortTypes, builder->getArrayAttr(newArgTypes)));
1230 newModuleAttrs.push_back(NamedAttribute(
1231 cache.sPortLocations, builder->getArrayAttr(newArgLocations)));
1233 newModuleAttrs.push_back(NamedAttribute(
1234 cache.sPortAnnotations, builder->getArrayAttr(newArgAnnotations)));
1236 newModuleAttrs.push_back(NamedAttribute(
1237 cache.sPortDomains, builder->getArrayAttr(newPortDomains)));
1240 module->setAttrs(newModuleAttrs);
1241 FModuleLike::fixupPortSymsArray(newArgSyms, context);
1242 module.setPortSymbols(newArgSyms);
1247bool TypeLoweringVisitor::visitDecl(WireOp op) {
1248 if (op.isForceable())
1251 auto clone = [&](
const FlatBundleFieldEntry &field,
1252 ArrayAttr attrs) -> Value {
1254 ->create<WireOp>(
mapLoweredType(op.getDataRaw().getType(), field.type),
1255 "", NameKindEnum::DroppableName, attrs, StringAttr{})
1258 return lowerProducer(op, clone);
1262bool TypeLoweringVisitor::visitDecl(RegOp op) {
1263 if (op.isForceable())
1266 auto clone = [&](
const FlatBundleFieldEntry &field,
1267 ArrayAttr attrs) -> Value {
1269 ->create<RegOp>(field.type, op.getClockVal(),
"",
1270 NameKindEnum::DroppableName, attrs, StringAttr{})
1273 return lowerProducer(op, clone);
1277bool TypeLoweringVisitor::visitDecl(RegResetOp op) {
1278 if (op.isForceable())
1281 auto clone = [&](
const FlatBundleFieldEntry &field,
1282 ArrayAttr attrs) -> Value {
1283 auto resetVal = getSubWhatever(op.getResetValue(), field.index);
1285 ->create<RegResetOp>(field.type, op.getClockVal(), op.getResetSignal(),
1286 resetVal,
"", NameKindEnum::DroppableName, attrs,
1290 return lowerProducer(op, clone);
1294bool TypeLoweringVisitor::visitDecl(NodeOp op) {
1295 if (op.isForceable())
1298 auto clone = [&](
const FlatBundleFieldEntry &field,
1299 ArrayAttr attrs) -> Value {
1300 auto input = getSubWhatever(op.getInput(), field.index);
1302 ->create<NodeOp>(input,
"", NameKindEnum::DroppableName, attrs)
1305 return lowerProducer(op, clone);
1309bool TypeLoweringVisitor::visitExpr(InvalidValueOp op) {
1310 auto clone = [&](
const FlatBundleFieldEntry &field,
1311 ArrayAttr attrs) -> Value {
1312 return builder->create<InvalidValueOp>(field.type);
1314 return lowerProducer(op, clone);
1318bool TypeLoweringVisitor::visitExpr(MuxPrimOp op) {
1319 auto clone = [&](
const FlatBundleFieldEntry &field,
1320 ArrayAttr attrs) -> Value {
1321 auto high = getSubWhatever(op.getHigh(), field.index);
1322 auto low = getSubWhatever(op.getLow(), field.index);
1323 return builder->create<MuxPrimOp>(op.getSel(), high, low);
1325 return lowerProducer(op, clone);
1329bool TypeLoweringVisitor::visitExpr(Mux2CellIntrinsicOp op) {
1330 auto clone = [&](
const FlatBundleFieldEntry &field,
1331 ArrayAttr attrs) -> Value {
1332 auto high = getSubWhatever(op.getHigh(), field.index);
1333 auto low = getSubWhatever(op.getLow(), field.index);
1334 return builder->create<Mux2CellIntrinsicOp>(op.getSel(), high, low);
1336 return lowerProducer(op, clone);
1340bool TypeLoweringVisitor::visitExpr(Mux4CellIntrinsicOp op) {
1341 auto clone = [&](
const FlatBundleFieldEntry &field,
1342 ArrayAttr attrs) -> Value {
1343 auto v3 = getSubWhatever(op.getV3(), field.index);
1344 auto v2 = getSubWhatever(op.getV2(), field.index);
1345 auto v1 = getSubWhatever(op.getV1(), field.index);
1346 auto v0 = getSubWhatever(op.getV0(), field.index);
1347 return builder->create<Mux4CellIntrinsicOp>(op.getSel(), v3, v2, v1, v0);
1349 return lowerProducer(op, clone);
1353bool TypeLoweringVisitor::visitUnrealizedConversionCast(
1354 mlir::UnrealizedConversionCastOp op) {
1355 auto clone = [&](
const FlatBundleFieldEntry &field,
1356 ArrayAttr attrs) -> Value {
1357 auto input = getSubWhatever(op.getOperand(0), field.index);
1358 return builder->create<mlir::UnrealizedConversionCastOp>(field.type, input)
1363 if (!type_isa<FIRRTLType>(op->getOperand(0).getType()))
1365 return lowerProducer(op, clone);
1369bool TypeLoweringVisitor::visitExpr(BitCastOp op) {
1370 Value srcLoweredVal = op.getInput();
1374 SmallVector<FlatBundleFieldEntry> fields;
1376 size_t uptoBits = 0;
1379 for (
const auto &field :
llvm::enumerate(fields)) {
1380 auto fieldBitwidth = *
getBitWidth(field.value().type);
1382 if (fieldBitwidth == 0)
1384 Value src = getSubWhatever(op.getInput(), field.index());
1386 src = builder->createOrFold<BitCastOp>(
1387 UIntType::get(context, fieldBitwidth), src);
1390 srcLoweredVal = src;
1392 if (type_isa<BundleType>(op.getInput().getType())) {
1394 builder->create<CatPrimOp>(ValueRange{srcLoweredVal, src});
1397 builder->create<CatPrimOp>(ValueRange{src, srcLoweredVal});
1401 uptoBits += fieldBitwidth;
1404 srcLoweredVal = builder->createOrFold<AsUIntPrimOp>(srcLoweredVal);
1408 if (type_isa<BundleType, FVectorType>(op.getResult().getType())) {
1410 size_t uptoBits = 0;
1411 auto aggregateBits = *
getBitWidth(op.getResult().getType());
1412 auto clone = [&](
const FlatBundleFieldEntry &field,
1413 ArrayAttr attrs) -> Value {
1419 return builder->create<InvalidValueOp>(field.type);
1424 if (type_isa<BundleType>(op.getResult().getType())) {
1426 srcLoweredVal, aggregateBits - uptoBits - 1,
1427 aggregateBits - uptoBits - fieldBits);
1430 srcLoweredVal, uptoBits + fieldBits - 1, uptoBits);
1432 uptoBits += fieldBits;
1433 return builder->create<BitCastOp>(field.type,
extractBits);
1435 return lowerProducer(op, clone);
1439 if (type_isa<SIntType>(op.getType()))
1440 srcLoweredVal = builder->create<AsSIntPrimOp>(srcLoweredVal);
1441 op.getResult().replaceAllUsesWith(srcLoweredVal);
1445bool TypeLoweringVisitor::visitExpr(RefSendOp op) {
1446 auto clone = [&](
const FlatBundleFieldEntry &field,
1447 ArrayAttr attrs) -> Value {
1448 return builder->create<RefSendOp>(
1449 getSubWhatever(op.getBase(), field.index));
1454 return lowerProducer(op, clone);
1457bool TypeLoweringVisitor::visitExpr(RefResolveOp op) {
1458 auto clone = [&](
const FlatBundleFieldEntry &field,
1459 ArrayAttr attrs) -> Value {
1460 Value src = getSubWhatever(op.getRef(), field.index);
1461 return builder->create<RefResolveOp>(src);
1465 return lowerProducer(op, clone, op.getRef().getType());
1468bool TypeLoweringVisitor::visitExpr(RefCastOp op) {
1469 auto clone = [&](
const FlatBundleFieldEntry &field,
1470 ArrayAttr attrs) -> Value {
1471 auto input = getSubWhatever(op.getInput(), field.index);
1472 return builder->create<RefCastOp>(RefType::get(field.type,
1473 op.getType().getForceable(),
1474 op.getType().getLayer()),
1477 return lowerProducer(op, clone);
1480bool TypeLoweringVisitor::visitDecl(InstanceOp op) {
1482 SmallVector<Type, 8> resultTypes;
1483 SmallVector<int64_t, 8> endFields;
1484 auto oldPortAnno = op.getPortAnnotations();
1485 SmallVector<Direction> newDirs;
1486 SmallVector<Attribute> newNames;
1488 SmallVector<Attribute> newDomains;
1489 SmallVector<Attribute> newPortAnno;
1491 cast<FModuleLike>(op.getReferencedOperation(symTbl)));
1493 endFields.push_back(0);
1494 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
1495 auto srcType = type_cast<FIRRTLType>(op.getType(i));
1498 SmallVector<FlatBundleFieldEntry, 8> fieldTypes;
1499 if (!
peelType(srcType, fieldTypes, mode)) {
1500 newDirs.push_back(op.getPortDirection(i));
1501 newNames.push_back(op.getPortName(i));
1502 newDomains.push_back(builder->getArrayAttr({}));
1503 resultTypes.push_back(srcType);
1504 newPortAnno.push_back(oldPortAnno[i]);
1507 auto oldName = op.getPortNameStr(i);
1508 auto oldDir = op.getPortDirection(i);
1510 for (
const auto &field : fieldTypes) {
1511 newDirs.push_back(
direction::get((
unsigned)oldDir ^ field.isOutput));
1512 newNames.push_back(builder->getStringAttr(oldName + field.suffix));
1513 newDomains.push_back(builder->getArrayAttr({}));
1515 auto annos = filterAnnotations(
1516 context, dyn_cast_or_null<ArrayAttr>(oldPortAnno[i]), srcType,
1518 newPortAnno.push_back(annos);
1521 endFields.push_back(resultTypes.size());
1531 auto newInstance = builder->create<InstanceOp>(
1532 resultTypes, op.getModuleNameAttr(), op.getNameAttr(),
1534 builder->getArrayAttr(newNames), builder->getArrayAttr(newDomains),
1535 op.getAnnotations(), builder->getArrayAttr(newPortAnno),
1536 op.getLayersAttr(), op.getLowerToBindAttr(), op.getDoNotPrintAttr(),
1537 sym ? hw::InnerSymAttr::get(sym) :
hw::InnerSymAttr());
1539 newInstance->setDiscardableAttrs(op->getDiscardableAttrDictionary());
1541 SmallVector<Value> lowered;
1542 for (
size_t aggIndex = 0, eAgg = op.getNumResults(); aggIndex != eAgg;
1545 for (
size_t fieldIndex = endFields[aggIndex],
1546 eField = endFields[aggIndex + 1];
1547 fieldIndex < eField; ++fieldIndex)
1548 lowered.push_back(newInstance.getResult(fieldIndex));
1549 if (lowered.size() != 1 ||
1550 op.getType(aggIndex) != resultTypes[endFields[aggIndex]])
1551 processUsers(op.getResult(aggIndex), lowered);
1553 op.getResult(aggIndex).replaceAllUsesWith(lowered[0]);
1558bool TypeLoweringVisitor::visitExpr(SubaccessOp op) {
1559 auto input = op.getInput();
1560 FVectorType vType = input.getType();
1563 if (vType.getNumElements() == 0) {
1564 Value inv = builder->create<InvalidValueOp>(vType.getElementType());
1565 op.replaceAllUsesWith(inv);
1570 if (ConstantOp arg =
1571 llvm::dyn_cast_or_null<ConstantOp>(op.getIndex().getDefiningOp())) {
1572 auto sio = builder->create<SubindexOp>(op.getInput(),
1573 arg.getValue().getExtValue());
1574 op.replaceAllUsesWith(sio.getResult());
1579 SmallVector<Value> inputs;
1580 inputs.reserve(vType.getNumElements());
1581 for (
int index = vType.getNumElements() - 1; index >= 0; index--)
1582 inputs.push_back(builder->create<SubindexOp>(input, index));
1584 Value multibitMux = builder->create<MultibitMuxOp>(op.getIndex(), inputs);
1585 op.replaceAllUsesWith(multibitMux);
1589bool TypeLoweringVisitor::visitExpr(VectorCreateOp op) {
1590 auto clone = [&](
const FlatBundleFieldEntry &field,
1591 ArrayAttr attrs) -> Value {
1592 return op.getOperand(field.index);
1594 return lowerProducer(op, clone);
1597bool TypeLoweringVisitor::visitExpr(BundleCreateOp op) {
1598 auto clone = [&](
const FlatBundleFieldEntry &field,
1599 ArrayAttr attrs) -> Value {
1600 return op.getOperand(field.index);
1602 return lowerProducer(op, clone);
1605bool TypeLoweringVisitor::visitExpr(ElementwiseOrPrimOp op) {
1606 auto clone = [&](
const FlatBundleFieldEntry &field,
1607 ArrayAttr attrs) -> Value {
1608 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1609 getSubWhatever(op.getRhs(), field.index)};
1610 return type_isa<BundleType, FVectorType>(field.type)
1611 ? (Value)builder->create<ElementwiseOrPrimOp>(field.type,
1613 : (Value)builder->create<OrPrimOp>(operands);
1616 return lowerProducer(op, clone);
1619bool TypeLoweringVisitor::visitExpr(ElementwiseAndPrimOp op) {
1620 auto clone = [&](
const FlatBundleFieldEntry &field,
1621 ArrayAttr attrs) -> Value {
1622 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1623 getSubWhatever(op.getRhs(), field.index)};
1624 return type_isa<BundleType, FVectorType>(field.type)
1625 ? (Value)builder->create<ElementwiseAndPrimOp>(field.type,
1627 : (Value)builder->create<AndPrimOp>(operands);
1630 return lowerProducer(op, clone);
1633bool TypeLoweringVisitor::visitExpr(ElementwiseXorPrimOp op) {
1634 auto clone = [&](
const FlatBundleFieldEntry &field,
1635 ArrayAttr attrs) -> Value {
1636 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1637 getSubWhatever(op.getRhs(), field.index)};
1638 return type_isa<BundleType, FVectorType>(field.type)
1639 ? (Value)builder->create<ElementwiseXorPrimOp>(field.type,
1641 : (Value)builder->create<XorPrimOp>(operands);
1644 return lowerProducer(op, clone);
1647bool TypeLoweringVisitor::visitExpr(MultibitMuxOp op) {
1648 auto clone = [&](
const FlatBundleFieldEntry &field,
1649 ArrayAttr attrs) -> Value {
1650 SmallVector<Value> newInputs;
1651 newInputs.reserve(op.getInputs().size());
1652 for (
auto input : op.getInputs()) {
1653 auto inputSub = getSubWhatever(input, field.index);
1654 newInputs.push_back(inputSub);
1656 return builder->create<MultibitMuxOp>(op.getIndex(), newInputs);
1658 return lowerProducer(op, clone);
1666struct LowerTypesPass
1667 :
public circt::firrtl::impl::LowerFIRRTLTypesBase<LowerTypesPass> {
1670 void runOnOperation()
override;
1675void LowerTypesPass::runOnOperation() {
1677 std::vector<FModuleLike> ops;
1679 auto &symTbl = getAnalysis<SymbolTable>();
1681 AttrCache cache(&getContext());
1683 DenseMap<FModuleLike, Convention> conventionTable;
1684 auto circuit = getOperation();
1685 for (
auto module : circuit.getOps<FModuleLike>()) {
1686 conventionTable.insert({module,
module.getConvention()});
1687 ops.push_back(module);
1691 auto lowerModules = [&](FModuleLike op) -> LogicalResult {
1693 Convention convention = Convention::Internal;
1694 if (
auto conventionAttr = dyn_cast_or_null<ConventionAttr>(
1695 op->getDiscardableAttr(
"body_type_lowering")))
1696 convention = conventionAttr.getValue();
1699 TypeLoweringVisitor(&getContext(), preserveAggregate, convention,
1700 preserveMemories, symTbl, cache, conventionTable);
1703 return LogicalResult::failure(tl.isFailed());
1706 auto result = failableParallelForEach(&getContext(), ops, lowerModules);
1709 signalPassFailure();
assert(baseType &&"element must be base type")
static SmallVector< Value > extractBits(OpBuilder &builder, Value val)
static void dump(DIModule &module, raw_indented_ostream &os)
static bool isPreservableAggregateType(Type type, PreserveAggregate::PreserveMode mode)
Return true if we can preserve the type.
static 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 SmallVector< Operation * > getSAWritePath(Operation *op)
Look through and collect subfields leading to a 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.
ResultType visitInvalidOp(Operation *op, ExtraArgs... args)
visitInvalidOp is an override point for non-FIRRTL dialect operations.
@ 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.
static Direction get(bool isOutput)
Return an output direction if isOutput is true, otherwise return an input direction.
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.
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)
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
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.