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; });
170static bool peelType(Type type, SmallVectorImpl<FlatBundleFieldEntry> &fields, {
…}
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 sEmpty = StringAttr::get(context,
"");
322 AttrCache(
const AttrCache &) =
default;
325 StringAttr nameAttr, nameKindAttr, sPortDirections, sPortNames, sPortTypes,
326 sPortSymbols, sPortLocations, sPortAnnotations, sEmpty;
331struct TypeLoweringVisitor :
public FIRRTLVisitor<TypeLoweringVisitor, bool> {
335 Convention bodyConvention,
337 SymbolTable &symTbl,
const AttrCache &cache,
338 const llvm::DenseMap<FModuleLike, Convention> &conventionTable)
339 : context(context), defaultAggregatePreservationMode(preserveAggregate),
340 memoryPreservationMode(memoryPreservationMode), symTbl(symTbl),
341 cache(cache), conventionTable(conventionTable) {
342 bodyAggregatePreservationMode = bodyConvention == Convention::Scalarized
344 : defaultAggregatePreservationMode;
352 void lowerModule(FModuleLike op);
354 bool lowerArg(FModuleLike module,
size_t argIndex,
size_t argsRemoved,
355 SmallVectorImpl<PortInfoWithIP> &newArgs,
356 SmallVectorImpl<Value> &lowering);
357 std::pair<Value, PortInfoWithIP>
358 addArg(Operation *module,
unsigned insertPt,
unsigned insertPtOffset,
359 FIRRTLType srcType,
const FlatBundleFieldEntry &field,
360 PortInfoWithIP &oldArg, hw::InnerSymAttr newSym);
363 bool visitDecl(FExtModuleOp op);
364 bool visitDecl(FModuleOp op);
365 bool visitDecl(InstanceOp op);
366 bool visitDecl(MemOp op);
367 bool visitDecl(NodeOp op);
368 bool visitDecl(RegOp op);
369 bool visitDecl(WireOp op);
370 bool visitDecl(RegResetOp op);
371 bool visitExpr(InvalidValueOp op);
372 bool visitExpr(SubaccessOp op);
373 bool visitExpr(VectorCreateOp op);
374 bool visitExpr(BundleCreateOp op);
375 bool visitExpr(ElementwiseAndPrimOp op);
376 bool visitExpr(ElementwiseOrPrimOp op);
377 bool visitExpr(ElementwiseXorPrimOp op);
378 bool visitExpr(MultibitMuxOp op);
379 bool visitExpr(MuxPrimOp op);
380 bool visitExpr(Mux2CellIntrinsicOp op);
381 bool visitExpr(Mux4CellIntrinsicOp op);
382 bool visitExpr(BitCastOp op);
383 bool visitExpr(RefSendOp op);
384 bool visitExpr(RefResolveOp op);
385 bool visitExpr(RefCastOp op);
386 bool visitStmt(ConnectOp op);
387 bool visitStmt(MatchingConnectOp op);
388 bool visitStmt(RefDefineOp op);
389 bool visitStmt(WhenOp op);
390 bool visitStmt(LayerBlockOp op);
391 bool visitUnrealizedConversionCast(mlir::UnrealizedConversionCastOp op);
393 bool isFailed()
const {
return encounteredError; }
396 if (
auto castOp = dyn_cast<mlir::UnrealizedConversionCastOp>(op))
397 return visitUnrealizedConversionCast(castOp);
402 void processUsers(Value val, ArrayRef<Value> mapping);
403 bool processSAPath(Operation *);
404 void lowerBlock(Block *);
405 void lowerSAWritePath(Operation *, ArrayRef<Operation *> writePath);
415 llvm::function_ref<Value(
const FlatBundleFieldEntry &, ArrayAttr)> clone,
420 ArrayAttr filterAnnotations(MLIRContext *ctxt, ArrayAttr annotations,
421 FIRRTLType srcType, FlatBundleFieldEntry field);
425 LogicalResult partitionSymbols(hw::InnerSymAttr sym,
FIRRTLType parentType,
426 SmallVectorImpl<hw::InnerSymAttr> &newSyms,
430 getPreservationModeForPorts(FModuleLike moduleLike);
431 Value getSubWhatever(Value val,
size_t index);
433 size_t uniqueIdx = 0;
434 std::string uniqueName() {
435 auto myID = uniqueIdx++;
436 return (Twine(
"__GEN_") + Twine(myID)).str();
439 MLIRContext *context;
447 ImplicitLocOpBuilder *builder;
453 const AttrCache &cache;
455 const llvm::DenseMap<FModuleLike, Convention> &conventionTable;
458 bool encounteredError =
false;
465TypeLoweringVisitor::getPreservationModeForPorts(FModuleLike module) {
466 auto lookup = conventionTable.find(module);
467 if (lookup == conventionTable.end())
468 return defaultAggregatePreservationMode;
469 switch (lookup->second) {
470 case Convention::Scalarized:
472 case Convention::Internal:
473 return defaultAggregatePreservationMode;
475 llvm_unreachable(
"Unknown convention");
476 return defaultAggregatePreservationMode;
479Value TypeLoweringVisitor::getSubWhatever(Value val,
size_t index) {
480 if (type_isa<BundleType>(val.getType()))
481 return builder->create<SubfieldOp>(val, index);
482 if (type_isa<FVectorType>(val.getType()))
483 return builder->create<SubindexOp>(val, index);
484 if (type_isa<RefType>(val.getType()))
485 return builder->create<RefSubOp>(val, index);
486 llvm_unreachable(
"Unknown aggregate type");
491bool TypeLoweringVisitor::processSAPath(Operation *op) {
494 if (writePath.empty())
497 lowerSAWritePath(op, writePath);
500 op->eraseOperands(0, 2);
502 for (
size_t i = 0; i < writePath.size(); ++i) {
503 if (writePath[i]->use_empty()) {
504 writePath[i]->erase();
512void TypeLoweringVisitor::lowerBlock(Block *block) {
514 for (
auto it = block->rbegin(), e = block->rend(); it != e;) {
516 builder->setInsertionPoint(&iop);
517 builder->setLoc(iop.getLoc());
518 bool removeOp = dispatchVisitor(&iop);
527ArrayAttr TypeLoweringVisitor::filterAnnotations(MLIRContext *ctxt,
528 ArrayAttr annotations,
530 FlatBundleFieldEntry field) {
531 SmallVector<Attribute> retval;
532 if (!annotations || annotations.empty())
533 return ArrayAttr::get(ctxt, retval);
534 for (
auto opAttr : annotations) {
536 auto fieldID = anno.getFieldID();
537 anno.removeMember(
"circt.fieldID");
542 retval.push_back(anno.getAttr());
547 if (fieldID < field.fieldID ||
552 if (
auto newFieldID = fieldID - field.fieldID) {
555 anno.setMember(
"circt.fieldID", builder->getI32IntegerAttr(newFieldID));
558 retval.push_back(anno.getAttr());
560 return ArrayAttr::get(ctxt, retval);
563LogicalResult TypeLoweringVisitor::partitionSymbols(
565 SmallVectorImpl<hw::InnerSymAttr> &newSyms, Location errorLoc) {
568 if (!sym || sym.empty())
571 auto *context = sym.getContext();
575 return mlir::emitError(errorLoc,
576 "unable to partition symbol on unsupported type ")
579 return TypeSwitch<FIRRTLType, LogicalResult>(baseType)
580 .Case<BundleType, FVectorType>([&](
auto aggType) -> LogicalResult {
584 hw::InnerSymPropertiesAttr prop;
588 SmallVector<BinningInfo> binning;
589 for (
auto prop : sym) {
590 auto fieldID = prop.getFieldID();
593 return mlir::emitError(errorLoc,
"unable to lower due to symbol ")
595 <<
" with target not preserved by lowering";
596 auto [index, relFieldID] = aggType.getIndexAndSubfieldID(fieldID);
597 binning.push_back({index, relFieldID, prop});
601 llvm::stable_sort(binning, [&](
auto &lhs,
auto &rhs) {
602 return std::tuple(lhs.index, lhs.relFieldID) <
603 std::tuple(rhs.index, rhs.relFieldID);
608 newSyms.resize(aggType.getNumElements());
609 for (
auto binIt = binning.begin(), binEnd = binning.end();
611 auto curIndex = binIt->index;
612 SmallVector<hw::InnerSymPropertiesAttr> propsForIndex;
614 while (binIt != binEnd && binIt->index == curIndex) {
615 propsForIndex.push_back(hw::InnerSymPropertiesAttr::get(
616 context, binIt->prop.getName(), binIt->relFieldID,
617 binIt->prop.getSymVisibility()));
621 assert(!newSyms[curIndex]);
622 newSyms[curIndex] = hw::InnerSymAttr::get(context, propsForIndex);
626 .Default([&](
auto ty) {
627 return mlir::emitError(
628 errorLoc,
"unable to partition symbol on unsupported type ")
633bool TypeLoweringVisitor::lowerProducer(
635 llvm::function_ref<Value(
const FlatBundleFieldEntry &, ArrayAttr)> clone,
639 srcType = op->getResult(0).getType();
640 auto srcFType = type_dyn_cast<FIRRTLType>(srcType);
643 SmallVector<FlatBundleFieldEntry, 8> fieldTypes;
645 if (!
peelType(srcFType, fieldTypes, bodyAggregatePreservationMode))
648 SmallVector<Value> lowered;
650 SmallString<16> loweredName;
651 auto nameKindAttr = op->getAttrOfType<NameKindEnumAttr>(cache.nameKindAttr);
653 if (
auto nameAttr = op->getAttrOfType<StringAttr>(cache.nameAttr))
654 loweredName = nameAttr.getValue();
655 auto baseNameLen = loweredName.size();
656 auto oldAnno = dyn_cast_or_null<ArrayAttr>(op->getAttr(
"annotations"));
658 SmallVector<hw::InnerSymAttr> fieldSyms(fieldTypes.size());
659 if (
auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(op)) {
660 if (failed(partitionSymbols(symOp.getInnerSymAttr(), srcFType, fieldSyms,
662 encounteredError =
true;
667 for (
const auto &[field, sym] :
llvm::zip_equal(fieldTypes, fieldSyms)) {
668 if (!loweredName.empty()) {
669 loweredName.resize(baseNameLen);
670 loweredName += field.suffix;
675 ArrayAttr loweredAttrs =
676 filterAnnotations(context, oldAnno, srcFType, field);
677 auto newVal = clone(field, loweredAttrs);
683 auto newSymOp = newVal.getDefiningOp<hw::InnerSymbolOpInterface>();
686 "op with inner symbol lowered to op that cannot take inner symbol");
687 newSymOp.setInnerSymbolAttr(sym);
691 if (
auto *newOp = newVal.getDefiningOp()) {
692 if (!loweredName.empty())
693 newOp->setAttr(cache.nameAttr, StringAttr::get(context, loweredName));
695 newOp->setAttr(cache.nameKindAttr, nameKindAttr);
698 newOp->setDiscardableAttrs(op->getDiscardableAttrDictionary());
700 lowered.push_back(newVal);
703 processUsers(op->getResult(0), lowered);
707void TypeLoweringVisitor::processUsers(Value val, ArrayRef<Value> mapping) {
708 for (
auto *user :
llvm::make_early_inc_range(val.getUsers())) {
709 TypeSwitch<Operation *, void>(user)
710 .Case<SubindexOp>([mapping](SubindexOp sio) {
711 Value repl = mapping[sio.getIndex()];
712 sio.replaceAllUsesWith(repl);
715 .Case<SubfieldOp>([mapping](SubfieldOp sfo) {
717 Value repl = mapping[sfo.getFieldIndex()];
718 sfo.replaceAllUsesWith(repl);
721 .Case<RefSubOp>([mapping](RefSubOp refSub) {
722 Value repl = mapping[refSub.getIndex()];
723 refSub.replaceAllUsesWith(repl);
726 .Default([&](
auto op) {
737 ImplicitLocOpBuilder b(user->getLoc(), user);
741 assert(llvm::none_of(mapping, [](
auto v) {
742 auto fbasetype = type_dyn_cast<FIRRTLBaseType>(v.getType());
743 return !fbasetype || fbasetype.containsReference();
747 TypeSwitch<Type, Value>(val.getType())
748 .template Case<FVectorType>([&](
auto vecType) {
749 return b.createOrFold<VectorCreateOp>(vecType, mapping);
751 .
template Case<BundleType>([&](
auto bundleType) {
752 return b.createOrFold<BundleCreateOp>(bundleType, mapping);
754 .Default([&](
auto _) -> Value {
return {}; });
756 user->emitError(
"unable to reconstruct source of type ")
758 encounteredError =
true;
761 user->replaceUsesOfWith(val, input);
766void TypeLoweringVisitor::lowerModule(FModuleLike op) {
767 if (
auto module = llvm::dyn_cast<FModuleOp>(*op))
769 else if (
auto extModule = llvm::dyn_cast<FExtModuleOp>(*op))
770 visitDecl(extModule);
776std::pair<Value, PortInfoWithIP>
777TypeLoweringVisitor::addArg(Operation *module,
unsigned insertPt,
779 const FlatBundleFieldEntry &field,
780 PortInfoWithIP &oldArg, hw::InnerSymAttr newSym) {
783 if (
auto mod = llvm::dyn_cast<FModuleOp>(module)) {
784 Block *body = mod.getBodyBlock();
786 newValue = body->insertArgument(insertPt, fieldType, oldArg.pi.loc);
790 auto name = builder->getStringAttr(oldArg.pi.name.getValue() + field.suffix);
793 auto newAnnotations = filterAnnotations(
794 context, oldArg.pi.annotations.getArrayAttr(), srcType, field);
796 auto direction = (
Direction)((
unsigned)oldArg.pi.direction ^ field.isOutput);
798 return std::make_pair(
800 PortInfoWithIP{
PortInfo{name, fieldType, direction, newSym, oldArg.pi.loc,
802 oldArg.internalPath});
806bool TypeLoweringVisitor::lowerArg(FModuleLike module,
size_t argIndex,
808 SmallVectorImpl<PortInfoWithIP> &newArgs,
809 SmallVectorImpl<Value> &lowering) {
812 SmallVector<FlatBundleFieldEntry> fieldTypes;
813 auto srcType = type_cast<FIRRTLType>(newArgs[argIndex].pi.type);
814 if (!
peelType(srcType, fieldTypes, getPreservationModeForPorts(module)))
818 if (
auto ip = newArgs[argIndex].internalPath; ip && ip->getPath()) {
819 ::mlir::emitError(newArgs[argIndex].pi.loc,
820 "cannot lower port with internal path");
821 encounteredError =
true;
825 SmallVector<hw::InnerSymAttr> fieldSyms(fieldTypes.size());
826 if (failed(partitionSymbols(newArgs[argIndex].pi.sym, srcType, fieldSyms,
827 newArgs[argIndex].pi.loc))) {
828 encounteredError =
true;
832 for (
const auto &[idx, field, fieldSym] :
833 llvm::enumerate(fieldTypes, fieldSyms)) {
834 auto newValue = addArg(module, 1 + argIndex + idx, argsRemoved, srcType,
835 field, newArgs[argIndex], fieldSym);
836 newArgs.insert(newArgs.begin() + 1 + argIndex + idx, newValue.second);
838 lowering.push_back(newValue.first);
843static Value
cloneAccess(ImplicitLocOpBuilder *builder, Operation *op,
845 if (
auto rop = llvm::dyn_cast<SubfieldOp>(op))
846 return builder->create<SubfieldOp>(rhs, rop.getFieldIndex());
847 if (
auto rop = llvm::dyn_cast<SubindexOp>(op))
848 return builder->create<SubindexOp>(rhs, rop.getIndex());
849 if (
auto rop = llvm::dyn_cast<SubaccessOp>(op))
850 return builder->create<SubaccessOp>(rhs, rop.getIndex());
851 op->emitError(
"Unknown accessor");
843static Value
cloneAccess(ImplicitLocOpBuilder *builder, Operation *op, {
…}
855void TypeLoweringVisitor::lowerSAWritePath(Operation *op,
856 ArrayRef<Operation *> writePath) {
857 SubaccessOp sao = cast<SubaccessOp>(writePath.back());
858 FVectorType saoType = sao.getInput().getType();
859 auto selectWidth = llvm::Log2_64_Ceil(saoType.getNumElements());
861 for (
size_t index = 0, e = saoType.getNumElements(); index < e; ++index) {
862 auto cond = builder->create<EQPrimOp>(
864 builder->createOrFold<ConstantOp>(UIntType::get(context, selectWidth),
865 APInt(selectWidth, index)));
866 builder->create<WhenOp>(cond,
false, [&]() {
868 Value leaf = builder->create<SubindexOp>(sao.getInput(), index);
869 for (
int i = writePath.size() - 2; i >= 0; --i) {
870 if (
auto access =
cloneAccess(builder, writePath[i], leaf))
873 encounteredError =
true;
884bool TypeLoweringVisitor::visitStmt(ConnectOp op) {
885 if (processSAPath(op))
889 SmallVector<FlatBundleFieldEntry> fields;
896 for (
const auto &field :
llvm::enumerate(fields)) {
897 Value src = getSubWhatever(op.getSrc(), field.index());
898 Value dest = getSubWhatever(op.getDest(), field.index());
899 if (field.value().isOutput)
900 std::swap(src, dest);
907bool TypeLoweringVisitor::visitStmt(MatchingConnectOp op) {
908 if (processSAPath(op))
912 SmallVector<FlatBundleFieldEntry> fields;
919 for (
const auto &field :
llvm::enumerate(fields)) {
920 Value src = getSubWhatever(op.getSrc(), field.index());
921 Value dest = getSubWhatever(op.getDest(), field.index());
922 if (field.value().isOutput)
923 std::swap(src, dest);
924 builder->create<MatchingConnectOp>(dest, src);
930bool TypeLoweringVisitor::visitStmt(RefDefineOp op) {
932 SmallVector<FlatBundleFieldEntry> fields;
934 if (!
peelType(op.getDest().getType(), fields, bodyAggregatePreservationMode))
938 for (
const auto &field :
llvm::enumerate(fields)) {
939 Value src = getSubWhatever(op.getSrc(), field.index());
940 Value dest = getSubWhatever(op.getDest(), field.index());
941 assert(!field.value().isOutput &&
"unexpected flip in reftype destination");
942 builder->create<RefDefineOp>(dest, src);
947bool TypeLoweringVisitor::visitStmt(WhenOp op) {
953 lowerBlock(&op.getThenBlock());
956 if (op.hasElseRegion())
957 lowerBlock(&op.getElseBlock());
962bool TypeLoweringVisitor::visitStmt(LayerBlockOp op) {
963 lowerBlock(op.getBody());
969bool TypeLoweringVisitor::visitDecl(MemOp op) {
971 SmallVector<FlatBundleFieldEntry> fields;
974 if (!
peelType(op.getDataType(), fields, memoryPreservationMode))
977 if (op.getInnerSym()) {
978 op->emitError() <<
"has a symbol, but no symbols may exist on aggregates "
979 "passed through LowerTypes";
980 encounteredError =
true;
984 SmallVector<MemOp> newMemories;
985 SmallVector<WireOp> oldPorts;
988 for (
unsigned int index = 0, end = op.getNumResults(); index <
end; ++index) {
989 auto result = op.getResult(index);
990 if (op.getPortKind(index) == MemOp::PortKind::Debug) {
991 op.emitOpError(
"cannot lower memory with debug port");
992 encounteredError =
true;
995 auto wire = builder->create<WireOp>(
997 (op.getName() +
"_" + op.getPortName(index).getValue()).str());
998 oldPorts.push_back(wire);
999 result.replaceAllUsesWith(wire.getResult());
1006 for (
const auto &field : fields) {
1008 if (!newMemForField) {
1009 op.emitError(
"failed cloning memory for field");
1010 encounteredError =
true;
1013 newMemories.push_back(newMemForField);
1016 for (
size_t index = 0, rend = op.getNumResults(); index < rend; ++index) {
1017 auto result = oldPorts[index].getResult();
1018 auto rType = type_cast<BundleType>(result.getType());
1019 for (
size_t fieldIndex = 0, fend = rType.getNumElements();
1020 fieldIndex != fend; ++fieldIndex) {
1021 auto name = rType.getElement(fieldIndex).name.getValue();
1022 auto oldField = builder->create<SubfieldOp>(result, fieldIndex);
1025 if (name ==
"data" || name ==
"mask" || name ==
"wdata" ||
1026 name ==
"wmask" || name ==
"rdata") {
1027 for (
const auto &field : fields) {
1028 auto realOldField = getSubWhatever(oldField, field.index);
1029 auto newField = getSubWhatever(
1030 newMemories[field.index].getResult(index), fieldIndex);
1031 if (rType.getElement(fieldIndex).isFlip)
1032 std::swap(realOldField, newField);
1036 for (
auto mem : newMemories) {
1038 builder->create<SubfieldOp>(mem.getResult(index), fieldIndex);
1047bool TypeLoweringVisitor::visitDecl(FExtModuleOp extModule) {
1048 ImplicitLocOpBuilder theBuilder(extModule.getLoc(), context);
1049 builder = &theBuilder;
1052 OpBuilder builder(context);
1054 auto internalPaths = extModule.getInternalPaths();
1057 SmallVector<unsigned> argsToRemove;
1058 SmallVector<PortInfoWithIP> newArgs;
1059 for (
auto [idx, pi] :
llvm::enumerate(extModule.getPorts())) {
1060 std::optional<InternalPathAttr> internalPath;
1062 internalPath = cast<InternalPathAttr>(internalPaths->getValue()[idx]);
1063 newArgs.push_back({pi, internalPath});
1066 for (
size_t argIndex = 0, argsRemoved = 0; argIndex < newArgs.size();
1068 SmallVector<Value> lowering;
1069 if (lowerArg(extModule, argIndex, argsRemoved, newArgs, lowering)) {
1070 argsToRemove.push_back(argIndex);
1077 for (
auto toRemove :
llvm::reverse(argsToRemove))
1078 newArgs.erase(newArgs.begin() + toRemove);
1080 SmallVector<NamedAttribute, 8> newModuleAttrs;
1083 for (
auto attr : extModule->getAttrDictionary())
1086 if (attr.
getName() !=
"portDirections" && attr.
getName() !=
"portNames" &&
1087 attr.
getName() !=
"portTypes" && attr.
getName() !=
"portAnnotations" &&
1088 attr.
getName() !=
"portSymbols" && attr.
getName() !=
"portLocations")
1089 newModuleAttrs.push_back(attr);
1091 SmallVector<Direction> newArgDirections;
1092 SmallVector<Attribute> newArgNames;
1093 SmallVector<Attribute, 8> newArgTypes;
1094 SmallVector<Attribute, 8> newArgSyms;
1095 SmallVector<Attribute, 8> newArgLocations;
1096 SmallVector<Attribute, 8> newArgAnnotations;
1097 SmallVector<Attribute, 8> newInternalPaths;
1099 auto emptyInternalPath = InternalPathAttr::get(context);
1100 for (
auto &port : newArgs) {
1101 newArgDirections.push_back(port.pi.direction);
1102 newArgNames.push_back(port.pi.name);
1103 newArgTypes.push_back(TypeAttr::get(port.pi.type));
1104 newArgSyms.push_back(port.pi.sym);
1105 newArgLocations.push_back(port.pi.loc);
1106 newArgAnnotations.push_back(port.pi.annotations.getArrayAttr());
1108 newInternalPaths.push_back(port.internalPath.value_or(emptyInternalPath));
1111 newModuleAttrs.push_back(
1112 NamedAttribute(cache.sPortDirections,
1115 newModuleAttrs.push_back(
1116 NamedAttribute(cache.sPortNames, builder.getArrayAttr(newArgNames)));
1118 newModuleAttrs.push_back(
1119 NamedAttribute(cache.sPortTypes, builder.getArrayAttr(newArgTypes)));
1121 newModuleAttrs.push_back(NamedAttribute(
1122 cache.sPortLocations, builder.getArrayAttr(newArgLocations)));
1124 newModuleAttrs.push_back(NamedAttribute(
1125 cache.sPortAnnotations, builder.getArrayAttr(newArgAnnotations)));
1128 extModule->setAttrs(newModuleAttrs);
1129 FModuleLike::fixupPortSymsArray(newArgSyms, context);
1130 extModule.setPortSymbols(newArgSyms);
1132 extModule.setInternalPathsAttr(builder.getArrayAttr(newInternalPaths));
1137bool TypeLoweringVisitor::visitDecl(FModuleOp module) {
1138 auto *body =
module.getBodyBlock();
1140 ImplicitLocOpBuilder theBuilder(module.getLoc(), context);
1141 builder = &theBuilder;
1147 llvm::BitVector argsToRemove;
1148 auto newArgs = llvm::map_to_vector(module.getPorts(), [](
auto pi) {
1149 return PortInfoWithIP{pi, std::nullopt};
1152 size_t argsRemoved = 0;
1153 for (
size_t argIndex = 0; argIndex < newArgs.size(); ++argIndex) {
1154 SmallVector<Value> lowerings;
1155 if (lowerArg(module, argIndex, argsRemoved, newArgs, lowerings)) {
1156 auto arg =
module.getArgument(argIndex);
1157 processUsers(arg, lowerings);
1158 argsToRemove.push_back(
true);
1161 argsToRemove.push_back(
false);
1166 if (argsRemoved != 0) {
1167 body->eraseArguments(argsToRemove);
1168 size_t size = newArgs.size();
1169 for (
size_t src = 0, dst = 0; src < size; ++src) {
1170 if (argsToRemove[src])
1172 newArgs[dst] = newArgs[src];
1175 newArgs.erase(newArgs.end() - argsRemoved, newArgs.end());
1178 SmallVector<NamedAttribute, 8> newModuleAttrs;
1181 for (
auto attr : module->getAttrDictionary())
1184 if (attr.
getName() !=
"portNames" && attr.
getName() !=
"portDirections" &&
1185 attr.
getName() !=
"portTypes" && attr.
getName() !=
"portAnnotations" &&
1186 attr.
getName() !=
"portSymbols" && attr.
getName() !=
"portLocations")
1187 newModuleAttrs.push_back(attr);
1189 SmallVector<Direction> newArgDirections;
1190 SmallVector<Attribute> newArgNames;
1191 SmallVector<Attribute> newArgTypes;
1192 SmallVector<Attribute> newArgSyms;
1193 SmallVector<Attribute> newArgLocations;
1194 SmallVector<Attribute, 8> newArgAnnotations;
1195 for (
auto &port : newArgs) {
1196 newArgDirections.push_back(port.pi.direction);
1197 newArgNames.push_back(port.pi.name);
1198 newArgTypes.push_back(TypeAttr::get(port.pi.type));
1199 newArgSyms.push_back(port.pi.sym);
1200 newArgLocations.push_back(port.pi.loc);
1201 newArgAnnotations.push_back(port.pi.annotations.getArrayAttr());
1204 newModuleAttrs.push_back(
1205 NamedAttribute(cache.sPortDirections,
1208 newModuleAttrs.push_back(
1209 NamedAttribute(cache.sPortNames, builder->getArrayAttr(newArgNames)));
1211 newModuleAttrs.push_back(
1212 NamedAttribute(cache.sPortTypes, builder->getArrayAttr(newArgTypes)));
1214 newModuleAttrs.push_back(NamedAttribute(
1215 cache.sPortLocations, builder->getArrayAttr(newArgLocations)));
1217 newModuleAttrs.push_back(NamedAttribute(
1218 cache.sPortAnnotations, builder->getArrayAttr(newArgAnnotations)));
1221 module->setAttrs(newModuleAttrs);
1222 FModuleLike::fixupPortSymsArray(newArgSyms, context);
1223 module.setPortSymbols(newArgSyms);
1228bool TypeLoweringVisitor::visitDecl(WireOp op) {
1229 if (op.isForceable())
1232 auto clone = [&](
const FlatBundleFieldEntry &field,
1233 ArrayAttr attrs) -> Value {
1235 ->create<WireOp>(
mapLoweredType(op.getDataRaw().getType(), field.type),
1236 "", NameKindEnum::DroppableName, attrs, StringAttr{})
1239 return lowerProducer(op, clone);
1243bool TypeLoweringVisitor::visitDecl(RegOp op) {
1244 if (op.isForceable())
1247 auto clone = [&](
const FlatBundleFieldEntry &field,
1248 ArrayAttr attrs) -> Value {
1250 ->create<RegOp>(field.type, op.getClockVal(),
"",
1251 NameKindEnum::DroppableName, attrs, StringAttr{})
1254 return lowerProducer(op, clone);
1258bool TypeLoweringVisitor::visitDecl(RegResetOp op) {
1259 if (op.isForceable())
1262 auto clone = [&](
const FlatBundleFieldEntry &field,
1263 ArrayAttr attrs) -> Value {
1264 auto resetVal = getSubWhatever(op.getResetValue(), field.index);
1266 ->create<RegResetOp>(field.type, op.getClockVal(), op.getResetSignal(),
1267 resetVal,
"", NameKindEnum::DroppableName, attrs,
1271 return lowerProducer(op, clone);
1275bool TypeLoweringVisitor::visitDecl(NodeOp op) {
1276 if (op.isForceable())
1279 auto clone = [&](
const FlatBundleFieldEntry &field,
1280 ArrayAttr attrs) -> Value {
1281 auto input = getSubWhatever(op.getInput(), field.index);
1283 ->create<NodeOp>(input,
"", NameKindEnum::DroppableName, attrs)
1286 return lowerProducer(op, clone);
1290bool TypeLoweringVisitor::visitExpr(InvalidValueOp op) {
1291 auto clone = [&](
const FlatBundleFieldEntry &field,
1292 ArrayAttr attrs) -> Value {
1293 return builder->create<InvalidValueOp>(field.type);
1295 return lowerProducer(op, clone);
1299bool TypeLoweringVisitor::visitExpr(MuxPrimOp op) {
1300 auto clone = [&](
const FlatBundleFieldEntry &field,
1301 ArrayAttr attrs) -> Value {
1302 auto high = getSubWhatever(op.getHigh(), field.index);
1303 auto low = getSubWhatever(op.getLow(), field.index);
1304 return builder->create<MuxPrimOp>(op.getSel(), high, low);
1306 return lowerProducer(op, clone);
1310bool TypeLoweringVisitor::visitExpr(Mux2CellIntrinsicOp op) {
1311 auto clone = [&](
const FlatBundleFieldEntry &field,
1312 ArrayAttr attrs) -> Value {
1313 auto high = getSubWhatever(op.getHigh(), field.index);
1314 auto low = getSubWhatever(op.getLow(), field.index);
1315 return builder->create<Mux2CellIntrinsicOp>(op.getSel(), high, low);
1317 return lowerProducer(op, clone);
1321bool TypeLoweringVisitor::visitExpr(Mux4CellIntrinsicOp op) {
1322 auto clone = [&](
const FlatBundleFieldEntry &field,
1323 ArrayAttr attrs) -> Value {
1324 auto v3 = getSubWhatever(op.getV3(), field.index);
1325 auto v2 = getSubWhatever(op.getV2(), field.index);
1326 auto v1 = getSubWhatever(op.getV1(), field.index);
1327 auto v0 = getSubWhatever(op.getV0(), field.index);
1328 return builder->create<Mux4CellIntrinsicOp>(op.getSel(), v3, v2, v1, v0);
1330 return lowerProducer(op, clone);
1334bool TypeLoweringVisitor::visitUnrealizedConversionCast(
1335 mlir::UnrealizedConversionCastOp op) {
1336 auto clone = [&](
const FlatBundleFieldEntry &field,
1337 ArrayAttr attrs) -> Value {
1338 auto input = getSubWhatever(op.getOperand(0), field.index);
1339 return builder->create<mlir::UnrealizedConversionCastOp>(field.type, input)
1344 if (!type_isa<FIRRTLType>(op->getOperand(0).getType()))
1346 return lowerProducer(op, clone);
1350bool TypeLoweringVisitor::visitExpr(BitCastOp op) {
1351 Value srcLoweredVal = op.getInput();
1355 SmallVector<FlatBundleFieldEntry> fields;
1357 size_t uptoBits = 0;
1360 for (
const auto &field :
llvm::enumerate(fields)) {
1361 auto fieldBitwidth = *
getBitWidth(field.value().type);
1363 if (fieldBitwidth == 0)
1365 Value src = getSubWhatever(op.getInput(), field.index());
1367 src = builder->createOrFold<BitCastOp>(
1368 UIntType::get(context, fieldBitwidth), src);
1371 srcLoweredVal = src;
1373 if (type_isa<BundleType>(op.getInput().getType())) {
1375 builder->create<CatPrimOp>(ValueRange{srcLoweredVal, src});
1378 builder->create<CatPrimOp>(ValueRange{src, srcLoweredVal});
1382 uptoBits += fieldBitwidth;
1385 srcLoweredVal = builder->createOrFold<AsUIntPrimOp>(srcLoweredVal);
1389 if (type_isa<BundleType, FVectorType>(op.getResult().getType())) {
1391 size_t uptoBits = 0;
1392 auto aggregateBits = *
getBitWidth(op.getResult().getType());
1393 auto clone = [&](
const FlatBundleFieldEntry &field,
1394 ArrayAttr attrs) -> Value {
1400 return builder->create<InvalidValueOp>(field.type);
1405 if (type_isa<BundleType>(op.getResult().getType())) {
1407 srcLoweredVal, aggregateBits - uptoBits - 1,
1408 aggregateBits - uptoBits - fieldBits);
1411 srcLoweredVal, uptoBits + fieldBits - 1, uptoBits);
1413 uptoBits += fieldBits;
1414 return builder->create<BitCastOp>(field.type,
extractBits);
1416 return lowerProducer(op, clone);
1420 if (type_isa<SIntType>(op.getType()))
1421 srcLoweredVal = builder->create<AsSIntPrimOp>(srcLoweredVal);
1422 op.getResult().replaceAllUsesWith(srcLoweredVal);
1426bool TypeLoweringVisitor::visitExpr(RefSendOp op) {
1427 auto clone = [&](
const FlatBundleFieldEntry &field,
1428 ArrayAttr attrs) -> Value {
1429 return builder->create<RefSendOp>(
1430 getSubWhatever(op.getBase(), field.index));
1435 return lowerProducer(op, clone);
1438bool TypeLoweringVisitor::visitExpr(RefResolveOp op) {
1439 auto clone = [&](
const FlatBundleFieldEntry &field,
1440 ArrayAttr attrs) -> Value {
1441 Value src = getSubWhatever(op.getRef(), field.index);
1442 return builder->create<RefResolveOp>(src);
1446 return lowerProducer(op, clone, op.getRef().getType());
1449bool TypeLoweringVisitor::visitExpr(RefCastOp op) {
1450 auto clone = [&](
const FlatBundleFieldEntry &field,
1451 ArrayAttr attrs) -> Value {
1452 auto input = getSubWhatever(op.getInput(), field.index);
1453 return builder->create<RefCastOp>(RefType::get(field.type,
1454 op.getType().getForceable(),
1455 op.getType().getLayer()),
1458 return lowerProducer(op, clone);
1461bool TypeLoweringVisitor::visitDecl(InstanceOp op) {
1463 SmallVector<Type, 8> resultTypes;
1464 SmallVector<int64_t, 8> endFields;
1465 auto oldPortAnno = op.getPortAnnotations();
1466 SmallVector<Direction> newDirs;
1467 SmallVector<Attribute> newNames;
1468 SmallVector<Attribute> newPortAnno;
1470 cast<FModuleLike>(op.getReferencedOperation(symTbl)));
1472 endFields.push_back(0);
1473 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
1474 auto srcType = type_cast<FIRRTLType>(op.getType(i));
1477 SmallVector<FlatBundleFieldEntry, 8> fieldTypes;
1478 if (!
peelType(srcType, fieldTypes, mode)) {
1479 newDirs.push_back(op.getPortDirection(i));
1480 newNames.push_back(op.getPortName(i));
1481 resultTypes.push_back(srcType);
1482 newPortAnno.push_back(oldPortAnno[i]);
1485 auto oldName = op.getPortNameStr(i);
1486 auto oldDir = op.getPortDirection(i);
1488 for (
const auto &field : fieldTypes) {
1489 newDirs.push_back(
direction::get((
unsigned)oldDir ^ field.isOutput));
1490 newNames.push_back(builder->getStringAttr(oldName + field.suffix));
1492 auto annos = filterAnnotations(
1493 context, dyn_cast_or_null<ArrayAttr>(oldPortAnno[i]), srcType,
1495 newPortAnno.push_back(annos);
1498 endFields.push_back(resultTypes.size());
1508 auto newInstance = builder->create<InstanceOp>(
1509 resultTypes, op.getModuleNameAttr(), op.getNameAttr(),
1511 builder->getArrayAttr(newNames), op.getAnnotations(),
1512 builder->getArrayAttr(newPortAnno), op.getLayersAttr(),
1513 op.getLowerToBindAttr(), op.getDoNotPrintAttr(),
1514 sym ? hw::InnerSymAttr::get(sym) :
hw::InnerSymAttr());
1516 newInstance->setDiscardableAttrs(op->getDiscardableAttrDictionary());
1518 SmallVector<Value> lowered;
1519 for (
size_t aggIndex = 0, eAgg = op.getNumResults(); aggIndex != eAgg;
1522 for (
size_t fieldIndex = endFields[aggIndex],
1523 eField = endFields[aggIndex + 1];
1524 fieldIndex < eField; ++fieldIndex)
1525 lowered.push_back(newInstance.getResult(fieldIndex));
1526 if (lowered.size() != 1 ||
1527 op.getType(aggIndex) != resultTypes[endFields[aggIndex]])
1528 processUsers(op.getResult(aggIndex), lowered);
1530 op.getResult(aggIndex).replaceAllUsesWith(lowered[0]);
1535bool TypeLoweringVisitor::visitExpr(SubaccessOp op) {
1536 auto input = op.getInput();
1537 FVectorType vType = input.getType();
1540 if (vType.getNumElements() == 0) {
1541 Value inv = builder->create<InvalidValueOp>(vType.getElementType());
1542 op.replaceAllUsesWith(inv);
1547 if (ConstantOp arg =
1548 llvm::dyn_cast_or_null<ConstantOp>(op.getIndex().getDefiningOp())) {
1549 auto sio = builder->create<SubindexOp>(op.getInput(),
1550 arg.getValue().getExtValue());
1551 op.replaceAllUsesWith(sio.getResult());
1556 SmallVector<Value> inputs;
1557 inputs.reserve(vType.getNumElements());
1558 for (
int index = vType.getNumElements() - 1; index >= 0; index--)
1559 inputs.push_back(builder->create<SubindexOp>(input, index));
1561 Value multibitMux = builder->create<MultibitMuxOp>(op.getIndex(), inputs);
1562 op.replaceAllUsesWith(multibitMux);
1566bool TypeLoweringVisitor::visitExpr(VectorCreateOp op) {
1567 auto clone = [&](
const FlatBundleFieldEntry &field,
1568 ArrayAttr attrs) -> Value {
1569 return op.getOperand(field.index);
1571 return lowerProducer(op, clone);
1574bool TypeLoweringVisitor::visitExpr(BundleCreateOp op) {
1575 auto clone = [&](
const FlatBundleFieldEntry &field,
1576 ArrayAttr attrs) -> Value {
1577 return op.getOperand(field.index);
1579 return lowerProducer(op, clone);
1582bool TypeLoweringVisitor::visitExpr(ElementwiseOrPrimOp op) {
1583 auto clone = [&](
const FlatBundleFieldEntry &field,
1584 ArrayAttr attrs) -> Value {
1585 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1586 getSubWhatever(op.getRhs(), field.index)};
1587 return type_isa<BundleType, FVectorType>(field.type)
1588 ? (Value)builder->create<ElementwiseOrPrimOp>(field.type,
1590 : (Value)builder->create<OrPrimOp>(operands);
1593 return lowerProducer(op, clone);
1596bool TypeLoweringVisitor::visitExpr(ElementwiseAndPrimOp op) {
1597 auto clone = [&](
const FlatBundleFieldEntry &field,
1598 ArrayAttr attrs) -> Value {
1599 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1600 getSubWhatever(op.getRhs(), field.index)};
1601 return type_isa<BundleType, FVectorType>(field.type)
1602 ? (Value)builder->create<ElementwiseAndPrimOp>(field.type,
1604 : (Value)builder->create<AndPrimOp>(operands);
1607 return lowerProducer(op, clone);
1610bool TypeLoweringVisitor::visitExpr(ElementwiseXorPrimOp op) {
1611 auto clone = [&](
const FlatBundleFieldEntry &field,
1612 ArrayAttr attrs) -> Value {
1613 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1614 getSubWhatever(op.getRhs(), field.index)};
1615 return type_isa<BundleType, FVectorType>(field.type)
1616 ? (Value)builder->create<ElementwiseXorPrimOp>(field.type,
1618 : (Value)builder->create<XorPrimOp>(operands);
1621 return lowerProducer(op, clone);
1624bool TypeLoweringVisitor::visitExpr(MultibitMuxOp op) {
1625 auto clone = [&](
const FlatBundleFieldEntry &field,
1626 ArrayAttr attrs) -> Value {
1627 SmallVector<Value> newInputs;
1628 newInputs.reserve(op.getInputs().size());
1629 for (
auto input : op.getInputs()) {
1630 auto inputSub = getSubWhatever(input, field.index);
1631 newInputs.push_back(inputSub);
1633 return builder->create<MultibitMuxOp>(op.getIndex(), newInputs);
1635 return lowerProducer(op, clone);
1643struct LowerTypesPass
1644 :
public circt::firrtl::impl::LowerFIRRTLTypesBase<LowerTypesPass> {
1648 preserveAggregate = preserveAggregateFlag;
1649 preserveMemories = preserveMemoriesFlag;
1651 void runOnOperation()
override;
1656void LowerTypesPass::runOnOperation() {
1658 std::vector<FModuleLike> ops;
1660 auto &symTbl = getAnalysis<SymbolTable>();
1662 AttrCache cache(&getContext());
1664 DenseMap<FModuleLike, Convention> conventionTable;
1665 auto circuit = getOperation();
1666 for (
auto module : circuit.getOps<FModuleLike>()) {
1667 conventionTable.insert({module,
module.getConvention()});
1668 ops.push_back(module);
1672 auto lowerModules = [&](FModuleLike op) -> LogicalResult {
1674 Convention convention = Convention::Internal;
1675 if (
auto conventionAttr = dyn_cast_or_null<ConventionAttr>(
1676 op->getDiscardableAttr(
"body_type_lowering")))
1677 convention = conventionAttr.getValue();
1680 TypeLoweringVisitor(&getContext(), preserveAggregate, convention,
1681 preserveMemories, symTbl, cache, conventionTable);
1684 return LogicalResult::failure(tl.isFailed());
1687 auto result = failableParallelForEach(&getContext(), ops, lowerModules);
1690 signalPassFailure();
1697 return std::make_unique<LowerTypesPass>(mode, memoryMode);
assert(baseType &&"element must be base type")
static 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.
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)
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.