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";
88 return mapBaseType(type, [&](
auto) {
return fieldType; });
93 auto ftype = type_dyn_cast<FIRRTLType>(type);
102 .
Case<BundleType>([&](
auto bundle) {
return false; })
103 .Case<FVectorType>([&](FVectorType vector) {
105 return vector.getElementType().isGround() &&
106 vector.getNumElements() > 1;
108 .Default([](
auto groundType) {
return true; });
115 .
Case<BundleType>([&](
auto bundle) {
return true; })
116 .Case<FVectorType>([&](FVectorType vector) {
119 .Default([](
auto groundType) {
return false; });
126 if (
auto refType = type_dyn_cast<RefType>(type)) {
128 if (refType.getForceable())
139 auto firrtlType = type_dyn_cast<FIRRTLBaseType>(type);
145 if (!firrtlType.isPassive() || firrtlType.containsAnalog() ||
157 llvm_unreachable(
"unexpected mode");
163static bool peelType(Type type, SmallVectorImpl<FlatBundleFieldEntry> &fields,
170 if (
auto refType = type_dyn_cast<RefType>(type))
171 type = refType.getType();
173 .
Case<BundleType>([&](
auto bundle) {
174 SmallString<16> tmpSuffix;
176 for (
size_t i = 0, e = bundle.getNumElements(); i < e; ++i) {
177 auto elt = bundle.getElement(i);
180 tmpSuffix.push_back(
'_');
181 tmpSuffix.append(elt.name.getValue());
182 fields.emplace_back(elt.type, i, bundle.getFieldID(i), tmpSuffix,
187 .Case<FVectorType>([&](
auto vector) {
189 for (
size_t i = 0, e = vector.getNumElements(); i != e; ++i) {
190 fields.emplace_back(vector.getElementType(), i, vector.getFieldID(i),
191 "_" + std::to_string(i),
false);
195 .Default([](
auto op) {
return false; });
201 SubaccessOp sao = llvm::dyn_cast<SubaccessOp>(op);
205 llvm::dyn_cast_or_null<ConstantOp>(sao.getIndex().getDefiningOp());
206 return arg && sao.getInput().getType().base().getNumElements() != 0;
211 SmallVector<Operation *> retval;
212 auto defOp = op->getOperand(0).getDefiningOp();
213 while (isa_and_nonnull<SubfieldOp, SubindexOp, SubaccessOp>(defOp)) {
214 retval.push_back(defOp);
215 defOp = defOp->getOperand(0).getDefiningOp();
225 FlatBundleFieldEntry field) {
226 SmallVector<Type, 8> ports;
227 SmallVector<Attribute, 8> portNames;
228 SmallVector<Attribute, 8> portLocations;
230 auto oldPorts = op.getPorts();
231 for (
size_t portIdx = 0, e = oldPorts.size(); portIdx < e; ++portIdx) {
232 auto port = oldPorts[portIdx];
234 MemOp::getTypeForPort(op.getDepth(), field.type, port.second));
235 portNames.push_back(port.first);
240 MemOp::create(*b, ports, op.getReadLatency(), op.getWriteLatency(),
241 op.getDepth(), op.getRuw(), b->getArrayAttr(portNames),
242 (op.getName() + field.suffix).str(), op.getNameKind(),
243 op.getAnnotations(), op.getPortAnnotations(),
244 op.getInnerSymAttr(), op.getInitAttr(), op.getPrefixAttr());
246 if (op.getInnerSym()) {
247 op.emitError(
"cannot split memory with symbol present");
251 SmallVector<Attribute> newAnnotations;
252 for (
size_t portIdx = 0, e = newMem.getNumResults(); portIdx < e; ++portIdx) {
253 auto portType = type_cast<BundleType>(newMem.getResult(portIdx).getType());
254 auto oldPortType = type_cast<BundleType>(op.getResult(portIdx).getType());
255 SmallVector<Attribute> portAnno;
256 for (
auto attr : newMem.getPortAnnotation(portIdx)) {
259 auto targetIndex = oldPortType.getIndexForFieldID(annoFieldID);
263 if (annoFieldID == oldPortType.getFieldID(targetIndex)) {
266 b->getI32IntegerAttr(portType.getFieldID(targetIndex)));
267 portAnno.push_back(anno.
getDict());
272 if (type_isa<BundleType>(oldPortType.getElement(targetIndex).type)) {
277 auto fieldID = field.fieldID + oldPortType.getFieldID(targetIndex);
278 if (annoFieldID >= fieldID &&
283 annoFieldID - fieldID + portType.getFieldID(targetIndex);
284 anno.
setMember(
"circt.fieldID", b->getI32IntegerAttr(newFieldID));
285 portAnno.push_back(anno.
getDict());
289 portAnno.push_back(attr);
291 newAnnotations.push_back(b->getArrayAttr(portAnno));
293 newMem.setAllPortAnnotations(newAnnotations);
303 AttrCache(MLIRContext *context) {
304 i64ty = IntegerType::get(context, 64);
305 nameAttr = StringAttr::get(context,
"name");
306 nameKindAttr = StringAttr::get(context,
"nameKind");
307 sPortDirections = StringAttr::get(context,
"portDirections");
308 sPortNames = StringAttr::get(context,
"portNames");
309 sPortTypes = StringAttr::get(context,
"portTypes");
310 sPortSymbols = StringAttr::get(context,
"portSymbols");
311 sPortLocations = StringAttr::get(context,
"portLocations");
312 sPortAnnotations = StringAttr::get(context,
"portAnnotations");
313 sPortDomains = StringAttr::get(context,
"domainInfo");
314 sEmpty = StringAttr::get(context,
"");
315 aEmpty = ArrayAttr::get(context, {});
317 AttrCache(
const AttrCache &) =
default;
320 StringAttr nameAttr, nameKindAttr, sPortDirections, sPortNames, sPortTypes,
321 sPortSymbols, sPortLocations, sPortAnnotations, sPortDomains, sEmpty;
327struct TypeLoweringVisitor :
public FIRRTLVisitor<TypeLoweringVisitor, bool> {
331 Convention bodyConvention,
333 SymbolTable &symTbl,
const AttrCache &cache,
334 const llvm::DenseMap<FModuleLike, Convention> &conventionTable)
335 : context(context), defaultAggregatePreservationMode(preserveAggregate),
336 memoryPreservationMode(memoryPreservationMode), symTbl(symTbl),
337 cache(cache), conventionTable(conventionTable) {
338 bodyAggregatePreservationMode = bodyConvention == Convention::Scalarized
340 : defaultAggregatePreservationMode;
348 void lowerModule(FModuleLike op);
350 bool lowerArg(FModuleLike module,
size_t argIndex,
size_t argsRemoved,
351 SmallVectorImpl<PortInfo> &newArgs,
352 SmallVectorImpl<Value> &lowering);
353 std::pair<Value, PortInfo> addArg(Operation *module,
unsigned insertPt,
355 const FlatBundleFieldEntry &field,
356 PortInfo &oldArg, hw::InnerSymAttr newSym);
359 bool visitDecl(FExtModuleOp op);
360 bool visitDecl(FModuleOp op);
361 bool visitDecl(InstanceOp op);
362 bool visitDecl(MemOp op);
363 bool visitDecl(NodeOp op);
364 bool visitDecl(RegOp op);
365 bool visitDecl(WireOp op);
366 bool visitDecl(RegResetOp op);
367 bool visitExpr(InvalidValueOp op);
368 bool visitExpr(SubaccessOp op);
369 bool visitExpr(VectorCreateOp op);
370 bool visitExpr(BundleCreateOp op);
371 bool visitExpr(ElementwiseAndPrimOp op);
372 bool visitExpr(ElementwiseOrPrimOp op);
373 bool visitExpr(ElementwiseXorPrimOp op);
374 bool visitExpr(MultibitMuxOp op);
375 bool visitExpr(MuxPrimOp op);
376 bool visitExpr(Mux2CellIntrinsicOp op);
377 bool visitExpr(Mux4CellIntrinsicOp op);
378 bool visitExpr(BitCastOp op);
379 bool visitExpr(RefSendOp op);
380 bool visitExpr(RefResolveOp op);
381 bool visitExpr(RefCastOp op);
382 bool visitStmt(ConnectOp op);
383 bool visitStmt(MatchingConnectOp op);
384 bool visitStmt(RefDefineOp op);
385 bool visitStmt(WhenOp op);
386 bool visitStmt(LayerBlockOp op);
387 bool visitUnrealizedConversionCast(mlir::UnrealizedConversionCastOp op);
389 bool isFailed()
const {
return encounteredError; }
392 if (
auto castOp = dyn_cast<mlir::UnrealizedConversionCastOp>(op))
393 return visitUnrealizedConversionCast(castOp);
398 void processUsers(Value val, ArrayRef<Value> mapping);
399 bool processSAPath(Operation *);
400 void lowerBlock(Block *);
401 void lowerSAWritePath(Operation *, ArrayRef<Operation *> writePath);
411 llvm::function_ref<Value(
const FlatBundleFieldEntry &, ArrayAttr)> clone,
416 ArrayAttr filterAnnotations(MLIRContext *ctxt, ArrayAttr annotations,
417 FIRRTLType srcType, FlatBundleFieldEntry field);
421 LogicalResult partitionSymbols(hw::InnerSymAttr sym,
FIRRTLType parentType,
422 SmallVectorImpl<hw::InnerSymAttr> &newSyms,
426 getPreservationModeForPorts(FModuleLike moduleLike);
427 Value getSubWhatever(Value val,
size_t index);
429 size_t uniqueIdx = 0;
430 std::string uniqueName() {
431 auto myID = uniqueIdx++;
432 return (Twine(
"__GEN_") + Twine(myID)).str();
435 MLIRContext *context;
443 ImplicitLocOpBuilder *builder;
449 const AttrCache &cache;
451 const llvm::DenseMap<FModuleLike, Convention> &conventionTable;
454 bool encounteredError =
false;
461TypeLoweringVisitor::getPreservationModeForPorts(FModuleLike module) {
462 auto lookup = conventionTable.find(module);
463 if (lookup == conventionTable.end())
464 return defaultAggregatePreservationMode;
465 switch (lookup->second) {
466 case Convention::Scalarized:
468 case Convention::Internal:
469 return defaultAggregatePreservationMode;
471 llvm_unreachable(
"Unknown convention");
472 return defaultAggregatePreservationMode;
475Value TypeLoweringVisitor::getSubWhatever(Value val,
size_t index) {
476 if (type_isa<BundleType>(val.getType()))
477 return SubfieldOp::create(*builder, val, index);
478 if (type_isa<FVectorType>(val.getType()))
479 return SubindexOp::create(*builder, val, index);
480 if (type_isa<RefType>(val.getType()))
481 return RefSubOp::create(*builder, val, index);
482 llvm_unreachable(
"Unknown aggregate type");
487bool TypeLoweringVisitor::processSAPath(Operation *op) {
490 if (writePath.empty())
493 lowerSAWritePath(op, writePath);
496 op->eraseOperands(0, 2);
498 for (
size_t i = 0; i < writePath.size(); ++i) {
499 if (writePath[i]->use_empty()) {
500 writePath[i]->erase();
508void TypeLoweringVisitor::lowerBlock(Block *block) {
510 for (
auto it = block->rbegin(), e = block->rend(); it != e;) {
512 builder->setInsertionPoint(&iop);
513 builder->setLoc(iop.getLoc());
514 bool removeOp = dispatchVisitor(&iop);
523ArrayAttr TypeLoweringVisitor::filterAnnotations(MLIRContext *ctxt,
524 ArrayAttr annotations,
526 FlatBundleFieldEntry field) {
527 SmallVector<Attribute> retval;
528 if (!annotations || annotations.empty())
529 return ArrayAttr::get(ctxt, retval);
530 for (
auto opAttr : annotations) {
532 auto fieldID = anno.getFieldID();
533 anno.removeMember(
"circt.fieldID");
538 retval.push_back(anno.getAttr());
543 if (fieldID < field.fieldID ||
548 if (
auto newFieldID = fieldID - field.fieldID) {
551 anno.setMember(
"circt.fieldID", builder->getI32IntegerAttr(newFieldID));
554 retval.push_back(anno.getAttr());
556 return ArrayAttr::get(ctxt, retval);
559LogicalResult TypeLoweringVisitor::partitionSymbols(
561 SmallVectorImpl<hw::InnerSymAttr> &newSyms, Location errorLoc) {
564 if (!sym || sym.empty())
567 auto *context = sym.getContext();
571 return mlir::emitError(errorLoc,
572 "unable to partition symbol on unsupported type ")
575 return TypeSwitch<FIRRTLType, LogicalResult>(baseType)
576 .Case<BundleType, FVectorType>([&](
auto aggType) -> LogicalResult {
580 hw::InnerSymPropertiesAttr prop;
584 SmallVector<BinningInfo> binning;
585 for (
auto prop : sym) {
586 auto fieldID = prop.getFieldID();
589 return mlir::emitError(errorLoc,
"unable to lower due to symbol ")
591 <<
" with target not preserved by lowering";
592 auto [index, relFieldID] = aggType.getIndexAndSubfieldID(fieldID);
593 binning.push_back({index, relFieldID, prop});
597 llvm::stable_sort(binning, [&](
auto &lhs,
auto &rhs) {
598 return std::tuple(lhs.index, lhs.relFieldID) <
599 std::tuple(rhs.index, rhs.relFieldID);
604 newSyms.resize(aggType.getNumElements());
605 for (
auto binIt = binning.begin(), binEnd = binning.end();
607 auto curIndex = binIt->index;
608 SmallVector<hw::InnerSymPropertiesAttr> propsForIndex;
610 while (binIt != binEnd && binIt->index == curIndex) {
611 propsForIndex.push_back(hw::InnerSymPropertiesAttr::get(
612 context, binIt->prop.getName(), binIt->relFieldID,
613 binIt->prop.getSymVisibility()));
617 assert(!newSyms[curIndex]);
618 newSyms[curIndex] = hw::InnerSymAttr::get(context, propsForIndex);
622 .Default([&](
auto ty) {
623 return mlir::emitError(
624 errorLoc,
"unable to partition symbol on unsupported type ")
629bool TypeLoweringVisitor::lowerProducer(
631 llvm::function_ref<Value(
const FlatBundleFieldEntry &, ArrayAttr)> clone,
635 srcType = op->getResult(0).getType();
636 auto srcFType = type_dyn_cast<FIRRTLType>(srcType);
639 SmallVector<FlatBundleFieldEntry, 8> fieldTypes;
641 if (!
peelType(srcFType, fieldTypes, bodyAggregatePreservationMode))
644 SmallVector<Value> lowered;
646 SmallString<16> loweredName;
647 auto nameKindAttr = op->getAttrOfType<NameKindEnumAttr>(cache.nameKindAttr);
649 if (
auto nameAttr = op->getAttrOfType<StringAttr>(cache.nameAttr))
650 loweredName = nameAttr.getValue();
651 auto baseNameLen = loweredName.size();
652 auto oldAnno = dyn_cast_or_null<ArrayAttr>(op->getAttr(
"annotations"));
654 SmallVector<hw::InnerSymAttr> fieldSyms(fieldTypes.size());
655 if (
auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(op)) {
656 if (failed(partitionSymbols(symOp.getInnerSymAttr(), srcFType, fieldSyms,
658 encounteredError =
true;
663 for (
const auto &[field, sym] :
llvm::zip_equal(fieldTypes, fieldSyms)) {
664 if (!loweredName.empty()) {
665 loweredName.resize(baseNameLen);
666 loweredName += field.suffix;
671 ArrayAttr loweredAttrs =
672 filterAnnotations(context, oldAnno, srcFType, field);
673 auto newVal = clone(field, loweredAttrs);
679 auto newSymOp = newVal.getDefiningOp<hw::InnerSymbolOpInterface>();
682 "op with inner symbol lowered to op that cannot take inner symbol");
683 newSymOp.setInnerSymbolAttr(sym);
687 if (
auto *newOp = newVal.getDefiningOp()) {
688 if (!loweredName.empty())
689 newOp->setAttr(cache.nameAttr, StringAttr::get(context, loweredName));
691 newOp->setAttr(cache.nameKindAttr, nameKindAttr);
694 newOp->setDiscardableAttrs(op->getDiscardableAttrDictionary());
696 lowered.push_back(newVal);
699 processUsers(op->getResult(0), lowered);
703void TypeLoweringVisitor::processUsers(Value val, ArrayRef<Value> mapping) {
704 for (
auto *user :
llvm::make_early_inc_range(val.getUsers())) {
705 TypeSwitch<Operation *, void>(user)
706 .Case<SubindexOp>([mapping](SubindexOp sio) {
707 Value repl = mapping[sio.getIndex()];
708 sio.replaceAllUsesWith(repl);
711 .Case<SubfieldOp>([mapping](SubfieldOp sfo) {
713 Value repl = mapping[sfo.getFieldIndex()];
714 sfo.replaceAllUsesWith(repl);
717 .Case<RefSubOp>([mapping](RefSubOp refSub) {
718 Value repl = mapping[refSub.getIndex()];
719 refSub.replaceAllUsesWith(repl);
722 .Default([&](
auto op) {
733 ImplicitLocOpBuilder b(user->getLoc(), user);
737 assert(llvm::none_of(mapping, [](
auto v) {
738 auto fbasetype = type_dyn_cast<FIRRTLBaseType>(v.getType());
739 return !fbasetype || fbasetype.containsReference();
743 TypeSwitch<Type, Value>(val.getType())
744 .template Case<FVectorType>([&](
auto vecType) {
745 return b.createOrFold<VectorCreateOp>(vecType, mapping);
747 .
template Case<BundleType>([&](
auto bundleType) {
748 return b.createOrFold<BundleCreateOp>(bundleType, mapping);
750 .Default([&](
auto _) -> Value {
return {}; });
752 user->emitError(
"unable to reconstruct source of type ")
754 encounteredError =
true;
757 user->replaceUsesOfWith(val, input);
762void TypeLoweringVisitor::lowerModule(FModuleLike op) {
763 if (
auto module = llvm::dyn_cast<FModuleOp>(*op))
765 else if (
auto extModule = llvm::dyn_cast<FExtModuleOp>(*op))
766 visitDecl(extModule);
772std::pair<Value, PortInfo>
773TypeLoweringVisitor::addArg(Operation *module,
unsigned insertPt,
775 const FlatBundleFieldEntry &field,
PortInfo &oldArg,
776 hw::InnerSymAttr newSym) {
779 if (
auto mod = llvm::dyn_cast<FModuleOp>(module)) {
780 Block *body = mod.getBodyBlock();
782 newValue = body->insertArgument(insertPt, fieldType, oldArg.
loc);
786 auto name = builder->getStringAttr(oldArg.
name.getValue() + field.suffix);
789 auto newAnnotations = filterAnnotations(
794 return std::make_pair(
795 newValue,
PortInfo{name, fieldType, direction, newSym, oldArg.
loc,
800bool TypeLoweringVisitor::lowerArg(FModuleLike module,
size_t argIndex,
802 SmallVectorImpl<PortInfo> &newArgs,
803 SmallVectorImpl<Value> &lowering) {
806 SmallVector<FlatBundleFieldEntry> fieldTypes;
807 auto srcType = type_cast<FIRRTLType>(newArgs[argIndex].type);
808 if (!
peelType(srcType, fieldTypes, getPreservationModeForPorts(module)))
811 SmallVector<hw::InnerSymAttr> fieldSyms(fieldTypes.size());
812 if (failed(partitionSymbols(newArgs[argIndex].sym, srcType, fieldSyms,
813 newArgs[argIndex].loc))) {
814 encounteredError =
true;
818 for (
const auto &[idx, field, fieldSym] :
819 llvm::enumerate(fieldTypes, fieldSyms)) {
820 auto newValue = addArg(module, 1 + argIndex + idx, argsRemoved, srcType,
821 field, newArgs[argIndex], fieldSym);
822 newArgs.insert(newArgs.begin() + 1 + argIndex + idx, newValue.second);
824 lowering.push_back(newValue.first);
829static Value
cloneAccess(ImplicitLocOpBuilder *builder, Operation *op,
831 if (
auto rop = llvm::dyn_cast<SubfieldOp>(op))
832 return SubfieldOp::create(*builder, rhs, rop.getFieldIndex());
833 if (
auto rop = llvm::dyn_cast<SubindexOp>(op))
834 return SubindexOp::create(*builder, rhs, rop.getIndex());
835 if (
auto rop = llvm::dyn_cast<SubaccessOp>(op))
836 return SubaccessOp::create(*builder, rhs, rop.getIndex());
837 op->emitError(
"Unknown accessor");
841void TypeLoweringVisitor::lowerSAWritePath(Operation *op,
842 ArrayRef<Operation *> writePath) {
843 SubaccessOp sao = cast<SubaccessOp>(writePath.back());
844 FVectorType saoType = sao.getInput().getType();
845 auto selectWidth = llvm::Log2_64_Ceil(saoType.getNumElements());
847 for (
size_t index = 0, e = saoType.getNumElements(); index < e; ++index) {
848 auto cond = EQPrimOp::create(
849 *builder, sao.getIndex(),
850 builder->createOrFold<ConstantOp>(UIntType::get(context, selectWidth),
851 APInt(selectWidth, index)));
852 WhenOp::create(*builder, cond,
false, [&]() {
854 Value leaf = SubindexOp::create(*builder, sao.getInput(), index);
855 for (
int i = writePath.size() - 2; i >= 0; --i) {
856 if (
auto access =
cloneAccess(builder, writePath[i], leaf))
859 encounteredError =
true;
870bool TypeLoweringVisitor::visitStmt(ConnectOp op) {
871 if (processSAPath(op))
875 SmallVector<FlatBundleFieldEntry> fields;
882 for (
const auto &field :
llvm::enumerate(fields)) {
883 Value src = getSubWhatever(op.getSrc(), field.index());
884 Value dest = getSubWhatever(op.getDest(), field.index());
885 if (field.value().isOutput)
886 std::swap(src, dest);
893bool TypeLoweringVisitor::visitStmt(MatchingConnectOp op) {
894 if (processSAPath(op))
898 SmallVector<FlatBundleFieldEntry> fields;
905 for (
const auto &field :
llvm::enumerate(fields)) {
906 Value src = getSubWhatever(op.getSrc(), field.index());
907 Value dest = getSubWhatever(op.getDest(), field.index());
908 if (field.value().isOutput)
909 std::swap(src, dest);
910 MatchingConnectOp::create(*builder, dest, src);
916bool TypeLoweringVisitor::visitStmt(RefDefineOp op) {
918 SmallVector<FlatBundleFieldEntry> fields;
920 if (!
peelType(op.getDest().getType(), fields, bodyAggregatePreservationMode))
924 for (
const auto &field :
llvm::enumerate(fields)) {
925 Value src = getSubWhatever(op.getSrc(), field.index());
926 Value dest = getSubWhatever(op.getDest(), field.index());
927 assert(!field.value().isOutput &&
"unexpected flip in reftype destination");
928 RefDefineOp::create(*builder, dest, src);
933bool TypeLoweringVisitor::visitStmt(WhenOp op) {
939 lowerBlock(&op.getThenBlock());
942 if (op.hasElseRegion())
943 lowerBlock(&op.getElseBlock());
948bool TypeLoweringVisitor::visitStmt(LayerBlockOp op) {
949 lowerBlock(op.getBody());
955bool TypeLoweringVisitor::visitDecl(MemOp op) {
957 SmallVector<FlatBundleFieldEntry> fields;
960 if (!
peelType(op.getDataType(), fields, memoryPreservationMode))
963 if (op.getInnerSym()) {
964 op->emitError() <<
"has a symbol, but no symbols may exist on aggregates "
965 "passed through LowerTypes";
966 encounteredError =
true;
970 SmallVector<MemOp> newMemories;
971 SmallVector<WireOp> oldPorts;
974 for (
unsigned int index = 0, end = op.getNumResults(); index <
end; ++index) {
975 auto result = op.getResult(index);
976 if (op.getPortKind(index) == MemOp::PortKind::Debug) {
977 op.emitOpError(
"cannot lower memory with debug port");
978 encounteredError =
true;
982 WireOp::create(*builder, result.getType(),
983 (op.getName() +
"_" + op.getPortName(index)).str());
984 oldPorts.push_back(wire);
985 result.replaceAllUsesWith(wire.getResult());
992 for (
const auto &field : fields) {
994 if (!newMemForField) {
995 op.emitError(
"failed cloning memory for field");
996 encounteredError =
true;
999 newMemories.push_back(newMemForField);
1002 for (
size_t index = 0, rend = op.getNumResults(); index < rend; ++index) {
1003 auto result = oldPorts[index].getResult();
1004 auto rType = type_cast<BundleType>(result.getType());
1005 for (
size_t fieldIndex = 0, fend = rType.getNumElements();
1006 fieldIndex != fend; ++fieldIndex) {
1007 auto name = rType.getElement(fieldIndex).name.getValue();
1008 auto oldField = SubfieldOp::create(*builder, result, fieldIndex);
1011 if (name ==
"data" || name ==
"mask" || name ==
"wdata" ||
1012 name ==
"wmask" || name ==
"rdata") {
1013 for (
const auto &field : fields) {
1014 auto realOldField = getSubWhatever(oldField, field.index);
1015 auto newField = getSubWhatever(
1016 newMemories[field.index].getResult(index), fieldIndex);
1017 if (rType.getElement(fieldIndex).isFlip)
1018 std::swap(realOldField, newField);
1022 for (
auto mem : newMemories) {
1024 SubfieldOp::create(*builder, mem.getResult(index), fieldIndex);
1033bool TypeLoweringVisitor::visitDecl(FExtModuleOp extModule) {
1034 ImplicitLocOpBuilder theBuilder(extModule.getLoc(), context);
1035 builder = &theBuilder;
1038 OpBuilder builder(context);
1041 SmallVector<unsigned> argsToRemove;
1042 auto newArgs = extModule.getPorts();
1044 for (
size_t argIndex = 0, argsRemoved = 0; argIndex < newArgs.size();
1046 SmallVector<Value> lowering;
1047 if (lowerArg(extModule, argIndex, argsRemoved, newArgs, lowering)) {
1048 argsToRemove.push_back(argIndex);
1055 for (
auto toRemove :
llvm::reverse(argsToRemove))
1056 newArgs.erase(newArgs.begin() + toRemove);
1058 SmallVector<NamedAttribute, 8> newModuleAttrs;
1061 for (
auto attr : extModule->getAttrDictionary())
1064 if (attr.
getName() !=
"portDirections" && attr.
getName() !=
"portNames" &&
1065 attr.
getName() !=
"portTypes" && attr.
getName() !=
"portAnnotations" &&
1066 attr.
getName() !=
"portSymbols" && attr.
getName() !=
"portLocations")
1067 newModuleAttrs.push_back(attr);
1069 SmallVector<Direction> newArgDirections;
1070 SmallVector<Attribute> newArgNames;
1071 SmallVector<Attribute, 8> newArgTypes;
1072 SmallVector<Attribute, 8> newArgSyms;
1073 SmallVector<Attribute, 8> newArgLocations;
1074 SmallVector<Attribute, 8> newArgAnnotations;
1075 SmallVector<Attribute, 8> newArgDomains;
1077 for (
auto &port : newArgs) {
1078 newArgDirections.push_back(port.direction);
1079 newArgNames.push_back(port.name);
1080 newArgTypes.push_back(TypeAttr::get(port.type));
1081 newArgSyms.push_back(port.sym);
1082 newArgLocations.push_back(port.loc);
1083 newArgAnnotations.push_back(port.annotations.getArrayAttr());
1084 if (
auto domains = port.domains)
1085 newArgDomains.push_back(domains);
1087 newArgDomains.push_back(cache.aEmpty);
1090 newModuleAttrs.push_back(
1091 NamedAttribute(cache.sPortDirections,
1094 newModuleAttrs.push_back(
1095 NamedAttribute(cache.sPortNames, builder.getArrayAttr(newArgNames)));
1097 newModuleAttrs.push_back(
1098 NamedAttribute(cache.sPortTypes, builder.getArrayAttr(newArgTypes)));
1100 newModuleAttrs.push_back(NamedAttribute(
1101 cache.sPortLocations, builder.getArrayAttr(newArgLocations)));
1103 newModuleAttrs.push_back(NamedAttribute(
1104 cache.sPortAnnotations, builder.getArrayAttr(newArgAnnotations)));
1106 newModuleAttrs.push_back(
1107 NamedAttribute(cache.sPortDomains, builder.getArrayAttr(newArgDomains)));
1110 extModule->setAttrs(newModuleAttrs);
1111 FModuleLike::fixupPortSymsArray(newArgSyms, context);
1112 extModule.setPortSymbols(newArgSyms);
1117bool TypeLoweringVisitor::visitDecl(FModuleOp module) {
1118 auto *body =
module.getBodyBlock();
1120 ImplicitLocOpBuilder theBuilder(module.getLoc(), context);
1121 builder = &theBuilder;
1127 llvm::BitVector argsToRemove;
1128 auto newArgs =
module.getPorts();
1130 size_t argsRemoved = 0;
1131 for (
size_t argIndex = 0; argIndex < newArgs.size(); ++argIndex) {
1132 SmallVector<Value> lowerings;
1133 if (lowerArg(module, argIndex, argsRemoved, newArgs, lowerings)) {
1134 auto arg =
module.getArgument(argIndex);
1135 processUsers(arg, lowerings);
1136 argsToRemove.push_back(
true);
1139 argsToRemove.push_back(
false);
1144 if (argsRemoved != 0) {
1145 body->eraseArguments(argsToRemove);
1146 size_t size = newArgs.size();
1147 for (
size_t src = 0, dst = 0; src < size; ++src) {
1148 if (argsToRemove[src])
1150 newArgs[dst] = newArgs[src];
1153 newArgs.erase(newArgs.end() - argsRemoved, newArgs.end());
1156 SmallVector<NamedAttribute, 8> newModuleAttrs;
1159 for (
auto attr : module->getAttrDictionary())
1162 if (attr.
getName() !=
"portNames" && attr.
getName() !=
"portDirections" &&
1163 attr.
getName() !=
"portTypes" && attr.
getName() !=
"portAnnotations" &&
1164 attr.
getName() !=
"portSymbols" && attr.
getName() !=
"portLocations")
1165 newModuleAttrs.push_back(attr);
1167 SmallVector<Direction> newArgDirections;
1168 SmallVector<Attribute> newArgNames;
1169 SmallVector<Attribute> newArgTypes;
1170 SmallVector<Attribute> newArgSyms;
1171 SmallVector<Attribute> newArgLocations;
1172 SmallVector<Attribute, 8> newArgAnnotations;
1173 SmallVector<Attribute> newPortDomains;
1174 for (
auto &port : newArgs) {
1175 newArgDirections.push_back(port.direction);
1176 newArgNames.push_back(port.name);
1177 newArgTypes.push_back(TypeAttr::get(port.type));
1178 newArgSyms.push_back(port.sym);
1179 newArgLocations.push_back(port.loc);
1180 newArgAnnotations.push_back(port.annotations.getArrayAttr());
1181 if (
auto domains = port.domains)
1182 newPortDomains.push_back(domains);
1184 newPortDomains.push_back(cache.aEmpty);
1187 newModuleAttrs.push_back(
1188 NamedAttribute(cache.sPortDirections,
1191 newModuleAttrs.push_back(
1192 NamedAttribute(cache.sPortNames, builder->getArrayAttr(newArgNames)));
1194 newModuleAttrs.push_back(
1195 NamedAttribute(cache.sPortTypes, builder->getArrayAttr(newArgTypes)));
1197 newModuleAttrs.push_back(NamedAttribute(
1198 cache.sPortLocations, builder->getArrayAttr(newArgLocations)));
1200 newModuleAttrs.push_back(NamedAttribute(
1201 cache.sPortAnnotations, builder->getArrayAttr(newArgAnnotations)));
1203 newModuleAttrs.push_back(NamedAttribute(
1204 cache.sPortDomains, builder->getArrayAttr(newPortDomains)));
1207 module->setAttrs(newModuleAttrs);
1208 FModuleLike::fixupPortSymsArray(newArgSyms, context);
1209 module.setPortSymbols(newArgSyms);
1214bool TypeLoweringVisitor::visitDecl(WireOp op) {
1215 if (op.isForceable())
1218 auto clone = [&](
const FlatBundleFieldEntry &field,
1219 ArrayAttr attrs) -> Value {
1220 return WireOp::create(*builder,
1222 "", NameKindEnum::DroppableName, attrs, StringAttr{})
1225 return lowerProducer(op, clone);
1229bool TypeLoweringVisitor::visitDecl(RegOp op) {
1230 if (op.isForceable())
1233 auto clone = [&](
const FlatBundleFieldEntry &field,
1234 ArrayAttr attrs) -> Value {
1235 return RegOp::create(*builder, field.type, op.getClockVal(),
"",
1236 NameKindEnum::DroppableName, attrs, StringAttr{})
1239 return lowerProducer(op, clone);
1243bool TypeLoweringVisitor::visitDecl(RegResetOp op) {
1244 if (op.isForceable())
1247 auto clone = [&](
const FlatBundleFieldEntry &field,
1248 ArrayAttr attrs) -> Value {
1249 auto resetVal = getSubWhatever(op.getResetValue(), field.index);
1250 return RegResetOp::create(*builder, field.type, op.getClockVal(),
1251 op.getResetSignal(), resetVal,
"",
1252 NameKindEnum::DroppableName, attrs, StringAttr{})
1255 return lowerProducer(op, clone);
1259bool TypeLoweringVisitor::visitDecl(NodeOp op) {
1260 if (op.isForceable())
1263 auto clone = [&](
const FlatBundleFieldEntry &field,
1264 ArrayAttr attrs) -> Value {
1265 auto input = getSubWhatever(op.getInput(), field.index);
1266 return NodeOp::create(*builder, input,
"", NameKindEnum::DroppableName,
1270 return lowerProducer(op, clone);
1274bool TypeLoweringVisitor::visitExpr(InvalidValueOp op) {
1275 auto clone = [&](
const FlatBundleFieldEntry &field,
1276 ArrayAttr attrs) -> Value {
1277 return InvalidValueOp::create(*builder, field.type);
1279 return lowerProducer(op, clone);
1283bool TypeLoweringVisitor::visitExpr(MuxPrimOp op) {
1284 auto clone = [&](
const FlatBundleFieldEntry &field,
1285 ArrayAttr attrs) -> Value {
1286 auto high = getSubWhatever(op.getHigh(), field.index);
1287 auto low = getSubWhatever(op.getLow(), field.index);
1288 return MuxPrimOp::create(*builder, op.getSel(), high, low);
1290 return lowerProducer(op, clone);
1294bool TypeLoweringVisitor::visitExpr(Mux2CellIntrinsicOp op) {
1295 auto clone = [&](
const FlatBundleFieldEntry &field,
1296 ArrayAttr attrs) -> Value {
1297 auto high = getSubWhatever(op.getHigh(), field.index);
1298 auto low = getSubWhatever(op.getLow(), field.index);
1299 return Mux2CellIntrinsicOp::create(*builder, op.getSel(), high, low);
1301 return lowerProducer(op, clone);
1305bool TypeLoweringVisitor::visitExpr(Mux4CellIntrinsicOp op) {
1306 auto clone = [&](
const FlatBundleFieldEntry &field,
1307 ArrayAttr attrs) -> Value {
1308 auto v3 = getSubWhatever(op.getV3(), field.index);
1309 auto v2 = getSubWhatever(op.getV2(), field.index);
1310 auto v1 = getSubWhatever(op.getV1(), field.index);
1311 auto v0 = getSubWhatever(op.getV0(), field.index);
1312 return Mux4CellIntrinsicOp::create(*builder, op.getSel(), v3, v2, v1, v0);
1314 return lowerProducer(op, clone);
1318bool TypeLoweringVisitor::visitUnrealizedConversionCast(
1319 mlir::UnrealizedConversionCastOp op) {
1320 auto clone = [&](
const FlatBundleFieldEntry &field,
1321 ArrayAttr attrs) -> Value {
1322 auto input = getSubWhatever(op.getOperand(0), field.index);
1323 return mlir::UnrealizedConversionCastOp::create(*builder, field.type, input)
1328 if (!type_isa<FIRRTLType>(op->getOperand(0).getType()))
1330 return lowerProducer(op, clone);
1334bool TypeLoweringVisitor::visitExpr(BitCastOp op) {
1335 Value srcLoweredVal = op.getInput();
1339 SmallVector<FlatBundleFieldEntry> fields;
1341 size_t uptoBits = 0;
1344 for (
const auto &field :
llvm::enumerate(fields)) {
1345 auto fieldBitwidth = *
getBitWidth(field.value().type);
1347 if (fieldBitwidth == 0)
1349 Value src = getSubWhatever(op.getInput(), field.index());
1351 src = builder->createOrFold<BitCastOp>(
1352 UIntType::get(context, fieldBitwidth), src);
1355 srcLoweredVal = src;
1357 if (type_isa<BundleType>(op.getInput().getType())) {
1359 CatPrimOp::create(*builder, ValueRange{srcLoweredVal, src});
1362 CatPrimOp::create(*builder, ValueRange{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 aggregateBits = *
getBitWidth(op.getResult().getType());
1377 auto clone = [&](
const FlatBundleFieldEntry &field,
1378 ArrayAttr attrs) -> Value {
1384 return InvalidValueOp::create(*builder, field.type);
1389 if (type_isa<BundleType>(op.getResult().getType())) {
1390 extractBits = BitsPrimOp::create(*builder, srcLoweredVal,
1391 aggregateBits - uptoBits - 1,
1392 aggregateBits - uptoBits - fieldBits);
1394 extractBits = BitsPrimOp::create(*builder, srcLoweredVal,
1395 uptoBits + fieldBits - 1, uptoBits);
1397 uptoBits += fieldBits;
1398 return BitCastOp::create(*builder, field.type,
extractBits);
1400 return lowerProducer(op, clone);
1404 if (type_isa<SIntType>(op.getType()))
1405 srcLoweredVal = AsSIntPrimOp::create(*builder, srcLoweredVal);
1406 op.getResult().replaceAllUsesWith(srcLoweredVal);
1410bool TypeLoweringVisitor::visitExpr(RefSendOp op) {
1411 auto clone = [&](
const FlatBundleFieldEntry &field,
1412 ArrayAttr attrs) -> Value {
1413 return RefSendOp::create(*builder,
1414 getSubWhatever(op.getBase(), field.index));
1419 return lowerProducer(op, clone);
1422bool TypeLoweringVisitor::visitExpr(RefResolveOp op) {
1423 auto clone = [&](
const FlatBundleFieldEntry &field,
1424 ArrayAttr attrs) -> Value {
1425 Value src = getSubWhatever(op.getRef(), field.index);
1426 return RefResolveOp::create(*builder, src);
1430 return lowerProducer(op, clone, op.getRef().getType());
1433bool TypeLoweringVisitor::visitExpr(RefCastOp op) {
1434 auto clone = [&](
const FlatBundleFieldEntry &field,
1435 ArrayAttr attrs) -> Value {
1436 auto input = getSubWhatever(op.getInput(), field.index);
1437 return RefCastOp::create(*builder,
1438 RefType::get(field.type,
1439 op.getType().getForceable(),
1440 op.getType().getLayer()),
1443 return lowerProducer(op, clone);
1446bool TypeLoweringVisitor::visitDecl(InstanceOp op) {
1448 SmallVector<Type, 8> resultTypes;
1449 SmallVector<int64_t, 8> endFields;
1450 auto oldPortAnno = op.getPortAnnotations();
1451 SmallVector<Direction> newDirs;
1452 SmallVector<Attribute> newNames;
1454 SmallVector<Attribute> newDomains;
1455 SmallVector<Attribute> newPortAnno;
1457 cast<FModuleLike>(op.getReferencedOperation(symTbl)));
1459 endFields.push_back(0);
1460 for (
size_t i = 0, e = op.getNumResults(); i != e; ++i) {
1461 auto srcType = type_cast<FIRRTLType>(op.getType(i));
1464 SmallVector<FlatBundleFieldEntry, 8> fieldTypes;
1465 if (!
peelType(srcType, fieldTypes, mode)) {
1466 newDirs.push_back(op.getPortDirection(i));
1467 newNames.push_back(op.getPortNameAttr(i));
1468 newDomains.push_back(builder->getArrayAttr({}));
1469 resultTypes.push_back(srcType);
1470 newPortAnno.push_back(oldPortAnno[i]);
1473 auto oldName = op.getPortName(i);
1474 auto oldDir = op.getPortDirection(i);
1476 for (
const auto &field : fieldTypes) {
1477 newDirs.push_back(
direction::get((
unsigned)oldDir ^ field.isOutput));
1478 newNames.push_back(builder->getStringAttr(oldName + field.suffix));
1479 newDomains.push_back(builder->getArrayAttr({}));
1481 auto annos = filterAnnotations(
1482 context, dyn_cast_or_null<ArrayAttr>(oldPortAnno[i]), srcType,
1484 newPortAnno.push_back(annos);
1487 endFields.push_back(resultTypes.size());
1497 auto newInstance = InstanceOp::create(
1498 *builder, resultTypes, op.getModuleNameAttr(), op.getNameAttr(),
1500 builder->getArrayAttr(newNames), builder->getArrayAttr(newDomains),
1501 op.getAnnotations(), builder->getArrayAttr(newPortAnno),
1502 op.getLayersAttr(), op.getLowerToBindAttr(), op.getDoNotPrintAttr(),
1503 sym ? hw::InnerSymAttr::get(sym) :
hw::InnerSymAttr());
1505 newInstance->setDiscardableAttrs(op->getDiscardableAttrDictionary());
1507 SmallVector<Value> lowered;
1508 for (
size_t aggIndex = 0, eAgg = op.getNumResults(); aggIndex != eAgg;
1511 for (
size_t fieldIndex = endFields[aggIndex],
1512 eField = endFields[aggIndex + 1];
1513 fieldIndex < eField; ++fieldIndex)
1514 lowered.push_back(newInstance.getResult(fieldIndex));
1515 if (lowered.size() != 1 ||
1516 op.getType(aggIndex) != resultTypes[endFields[aggIndex]])
1517 processUsers(op.getResult(aggIndex), lowered);
1519 op.getResult(aggIndex).replaceAllUsesWith(lowered[0]);
1524bool TypeLoweringVisitor::visitExpr(SubaccessOp op) {
1525 auto input = op.getInput();
1526 FVectorType vType = input.getType();
1529 if (vType.getNumElements() == 0) {
1530 Value inv = InvalidValueOp::create(*builder, vType.getElementType());
1531 op.replaceAllUsesWith(inv);
1536 if (ConstantOp arg =
1537 llvm::dyn_cast_or_null<ConstantOp>(op.getIndex().getDefiningOp())) {
1538 auto sio = SubindexOp::create(*builder, op.getInput(),
1539 arg.getValue().getExtValue());
1540 op.replaceAllUsesWith(sio.getResult());
1545 SmallVector<Value> inputs;
1546 inputs.reserve(vType.getNumElements());
1547 for (
int index = vType.getNumElements() - 1; index >= 0; index--)
1548 inputs.push_back(SubindexOp::create(*builder, input, index));
1550 Value multibitMux = MultibitMuxOp::create(*builder, op.getIndex(), inputs);
1551 op.replaceAllUsesWith(multibitMux);
1555bool TypeLoweringVisitor::visitExpr(VectorCreateOp op) {
1556 auto clone = [&](
const FlatBundleFieldEntry &field,
1557 ArrayAttr attrs) -> Value {
1558 return op.getOperand(field.index);
1560 return lowerProducer(op, clone);
1563bool TypeLoweringVisitor::visitExpr(BundleCreateOp op) {
1564 auto clone = [&](
const FlatBundleFieldEntry &field,
1565 ArrayAttr attrs) -> Value {
1566 return op.getOperand(field.index);
1568 return lowerProducer(op, clone);
1571bool TypeLoweringVisitor::visitExpr(ElementwiseOrPrimOp op) {
1572 auto clone = [&](
const FlatBundleFieldEntry &field,
1573 ArrayAttr attrs) -> Value {
1574 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1575 getSubWhatever(op.getRhs(), field.index)};
1576 return type_isa<BundleType, FVectorType>(field.type)
1577 ? (Value)ElementwiseOrPrimOp::create(*builder, field.type,
1579 : (Value)OrPrimOp::create(*builder, operands);
1582 return lowerProducer(op, clone);
1585bool TypeLoweringVisitor::visitExpr(ElementwiseAndPrimOp op) {
1586 auto clone = [&](
const FlatBundleFieldEntry &field,
1587 ArrayAttr attrs) -> Value {
1588 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1589 getSubWhatever(op.getRhs(), field.index)};
1590 return type_isa<BundleType, FVectorType>(field.type)
1591 ? (Value)ElementwiseAndPrimOp::create(*builder, field.type,
1593 : (Value)AndPrimOp::create(*builder, operands);
1596 return lowerProducer(op, clone);
1599bool TypeLoweringVisitor::visitExpr(ElementwiseXorPrimOp op) {
1600 auto clone = [&](
const FlatBundleFieldEntry &field,
1601 ArrayAttr attrs) -> Value {
1602 Value operands[] = {getSubWhatever(op.getLhs(), field.index),
1603 getSubWhatever(op.getRhs(), field.index)};
1604 return type_isa<BundleType, FVectorType>(field.type)
1605 ? (Value)ElementwiseXorPrimOp::create(*builder, field.type,
1607 : (Value)XorPrimOp::create(*builder, operands);
1610 return lowerProducer(op, clone);
1613bool TypeLoweringVisitor::visitExpr(MultibitMuxOp op) {
1614 auto clone = [&](
const FlatBundleFieldEntry &field,
1615 ArrayAttr attrs) -> Value {
1616 SmallVector<Value> newInputs;
1617 newInputs.reserve(op.getInputs().size());
1618 for (
auto input : op.getInputs()) {
1619 auto inputSub = getSubWhatever(input, field.index);
1620 newInputs.push_back(inputSub);
1622 return MultibitMuxOp::create(*builder, op.getIndex(), newInputs);
1624 return lowerProducer(op, clone);
1632struct LowerTypesPass
1633 :
public circt::firrtl::impl::LowerFIRRTLTypesBase<LowerTypesPass> {
1636 void runOnOperation()
override;
1641void LowerTypesPass::runOnOperation() {
1644 std::vector<FModuleLike> ops;
1646 auto &symTbl = getAnalysis<SymbolTable>();
1648 AttrCache cache(&getContext());
1650 DenseMap<FModuleLike, Convention> conventionTable;
1651 auto circuit = getOperation();
1652 for (
auto module : circuit.getOps<FModuleLike>()) {
1653 conventionTable.insert({module,
module.getConvention()});
1654 ops.push_back(module);
1658 auto lowerModules = [&](FModuleLike op) -> LogicalResult {
1660 Convention convention = Convention::Internal;
1661 if (
auto conventionAttr = dyn_cast_or_null<ConventionAttr>(
1662 op->getDiscardableAttr(
"body_type_lowering")))
1663 convention = conventionAttr.getValue();
1666 TypeLoweringVisitor(&getContext(), preserveAggregate, convention,
1667 preserveMemories, symTbl, cache, conventionTable);
1670 return LogicalResult::failure(tl.isFailed());
1673 auto result = failableParallelForEach(&getContext(), ops, lowerModules);
1676 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.
#define CIRCT_DEBUG_SCOPED_PASS_LOGGER(PASS)
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
ArrayAttr getArrayAttr() const
Return this annotation set as an ArrayAttr.
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.
This holds the name and type that describes the module's ports.
AnnotationSet annotations