19#include "mlir/IR/ImplicitLocOpBuilder.h"
20#include "llvm/ADT/SmallString.h"
21#include "llvm/ADT/TypeSwitch.h"
24using namespace firrtl;
31 Value &cached =
cache[type];
33 cached =
builder.create<UnknownValueOp>(type);
42 Value src,
bool warnOnTruncation) {
43 ImplicitLocOpBuilder locBuilder(loc, builder.getInsertionBlock(),
44 builder.getInsertionPoint());
45 emitConnect(locBuilder, dst, src, warnOnTruncation);
46 builder.restoreInsertionPoint(locBuilder.saveInsertionPoint());
50 Value src,
bool warnOnTruncation) {
52 builder, dst, src, [&] {
return builder.getLoc(); }, warnOnTruncation);
55template <
typename ATy,
typename IndexOp,
bool isBundle >
59 llvm::function_ref<Location()> getDiagLoc,
60 bool warnOnTruncation) {
61 auto dstAggTy = type_dyn_cast<ATy>(dstFType);
64 auto srcAggTy = type_dyn_cast<ATy>(srcFType);
73 ConnectOp::create(builder, dst, src);
78 auto dstField = IndexOp::create(builder, dst, i);
79 auto srcField = IndexOp::create(builder, src, i);
80 if constexpr (isBundle) {
81 if (dstAggTy.getElement(i).isFlip)
82 std::swap(dstField, srcField);
84 emitConnect(builder, dstField, srcField, getDiagLoc, warnOnTruncation);
93 llvm::function_ref<Location()> getDiagLoc,
94 bool warnOnTruncation) {
95 auto dstFType = type_cast<FIRRTLType>(dst.getType());
96 auto srcFType = type_cast<FIRRTLType>(src.getType());
97 auto dstType = type_dyn_cast<FIRRTLBaseType>(dstFType);
98 auto srcType = type_dyn_cast<FIRRTLBaseType>(srcFType);
102 if (type_isa<RefType>(dstFType)) {
103 if (dstFType != srcFType)
104 src = RefCastOp::create(builder, dstFType, src);
105 RefDefineOp::create(builder, dst, src);
106 }
else if (type_isa<PropertyType>(dstFType) &&
107 type_isa<PropertyType>(srcFType)) {
109 PropAssignOp::create(builder, dst, src);
110 }
else if (type_isa<DomainType>(dstFType) &&
111 type_isa<DomainType>(srcFType)) {
112 DomainDefineOp::create(builder, dst, src);
113 }
else if (failed(connectIfAggregates<OpenBundleType, OpenSubfieldOp, true>(
114 builder, dst, dstFType, src, srcFType, getDiagLoc,
115 warnOnTruncation)) &&
117 connectIfAggregates<OpenVectorType, OpenSubindexOp, false>(
118 builder, dst, dstFType, src, srcFType, getDiagLoc,
119 warnOnTruncation))) {
121 ConnectOp::create(builder, dst, src);
127 if (isa<AnalogType>(dstType)) {
128 AttachOp::create(builder, ArrayRef{dst, src});
133 if (dstType == srcType && dstType.isPassive() &&
134 !dstType.hasUninferredWidth() && !dstType.containsAnalog()) {
135 MatchingConnectOp::create(builder, dst, src);
139 if (succeeded(connectIfAggregates<BundleType, SubfieldOp, true>(
140 builder, dst, dstFType, src, srcFType, getDiagLoc,
141 warnOnTruncation)) ||
142 succeeded(connectIfAggregates<FVectorType, SubindexOp, false>(
143 builder, dst, dstFType, src, srcFType, getDiagLoc, warnOnTruncation)))
146 if ((dstType.hasUninferredReset() || srcType.hasUninferredReset()) &&
147 dstType != srcType) {
148 srcType = dstType.getConstType(srcType.isConst());
149 src = UninferredResetCastOp::create(builder, srcType, src);
153 auto dstWidth = dstType.getBitWidthOrSentinel();
154 auto srcWidth = srcType.getBitWidthOrSentinel();
155 if (dstWidth < 0 || srcWidth < 0) {
162 if (dstType != srcType && dstType.getWidthlessType() != srcType &&
164 src = ConstCastOp::create(builder, dstType.getWidthlessType(), src);
167 ConnectOp::create(builder, dst, src);
172 if (dstWidth < srcWidth) {
173 if (warnOnTruncation)
174 mlir::emitWarning(getDiagLoc())
175 <<
"RHS width " << srcWidth <<
" exceeds LHS width " << dstWidth
176 <<
", inserting implicit truncation";
180 type_cast<IntType>(dstType).
getConstType(srcType.isConst());
181 bool isSignedDest = tmpType.
isSigned();
184 UIntType::get(dstType.getContext(), dstWidth, srcType.isConst());
185 src = TailPrimOp::create(builder, tmpType, src, srcWidth - dstWidth);
188 src = AsSIntPrimOp::create(builder,
189 dstType.getConstType(tmpType.
isConst()), src);
190 }
else if (srcWidth < dstWidth) {
192 src = PadPrimOp::create(builder, src, dstWidth);
195 if (
auto srcType = type_cast<FIRRTLBaseType>(src.getType());
196 srcType && dstType != srcType &&
198 src = ConstCastOp::create(builder, dstType, src);
203 if (dstType == src.getType() && dstType.isPassive() &&
204 !dstType.hasUninferredWidth()) {
205 MatchingConnectOp::create(builder, dst, src);
207 ConnectOp::create(builder, dst, src);
211 auto intType = type_cast<IntType>(type);
212 assert((!intType.hasWidth() ||
213 (
unsigned)intType.getWidthOrSentinel() == value.getBitWidth()) &&
214 "value / type width mismatch");
216 intType.isSigned() ? IntegerType::Signed : IntegerType::Unsigned;
218 IntegerType::get(type.getContext(), value.getBitWidth(), intSign);
219 return IntegerAttr::get(attrType, value);
225 int32_t width = abs(type_cast<IntType>(type).getWidthOrSentinel());
232 int32_t width = abs(type_cast<IntType>(type).getWidthOrSentinel());
234 type, APInt(width, -1,
false,
true));
240 std::optional<APInt> foldedValue) {
245 return initial.getValue() == *foldedValue;
251 for (
auto *user : value.getUsers())
252 if (
auto propassign = dyn_cast<PropAssignOp>(user))
253 if (propassign.getDest() == value)
268 for (
auto *user : val.getUsers()) {
269 if (
auto connect = dyn_cast<FConnectLike>(user)) {
270 if (connect.getDest() != val)
272 return connect.getSrc();
279 bool lookThroughNodes,
280 bool lookThroughCasts) {
285 auto updateVal = [&](Value thisVal) {
286 for (
auto *user : thisVal.getUsers()) {
287 if (
auto connect = dyn_cast<FConnectLike>(user)) {
288 if (connect.getDest() != val)
290 val = connect.getSrc();
300 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
301 FModuleOp op = cast<FModuleOp>(val.getParentBlock()->getParentOp());
302 auto direction = op.getPortDirection(blockArg.getArgNumber());
310 auto *op = val.getDefiningOp();
313 if (
auto inst = dyn_cast<InstanceOp>(op)) {
314 auto resultNo = cast<OpResult>(val).getResultNumber();
317 return inst.getResult(resultNo);
324 updateVal(op->getResult(0));
329 if (lookThroughNodes && isa<NodeOp>(op)) {
330 val = cast<NodeOp>(op).getInput();
334 if (lookThroughCasts &&
335 isa<AsUIntPrimOp, AsSIntPrimOp, AsClockPrimOp, AsAsyncResetPrimOp>(
337 val = op->getOperand(0);
342 if (isa<PadPrimOp, TailPrimOp>(op)) {
343 val = op->getOperand(0);
358 bool lookThroughNodes,
bool lookThroughCasts,
362 assert(value.getType().isPassive() &&
"this code was not tested with flips");
373 struct StackElement {
375 : dst(dst), src(src), current(current), it(current.user_begin()),
388 Value::user_iterator it;
392 SmallVector<StackElement> workStack;
398 auto value = src.getValue();
399 workStack.emplace_back(dst, src, value, src.
getFieldID());
405 auto fieldRef = original;
413 auto val = fieldRef.getValue();
416 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
417 auto *parent = val.getParentBlock()->getParentOp();
418 auto module = cast<FModuleLike>(parent);
419 auto direction =
module.getPortDirection(blockArg.getArgNumber());
422 if (!callback(original, fieldRef))
426 addToWorklist(original, fieldRef);
430 auto *op = val.getDefiningOp();
433 if (
auto inst = dyn_cast<InstanceOp>(op)) {
434 auto resultNo = cast<OpResult>(val).getResultNumber();
437 if (!callback(original, fieldRef))
441 addToWorklist(original, fieldRef);
447 addToWorklist(original, fieldRef);
452 if (lookThroughNodes && isa<NodeOp>(op)) {
453 auto input = cast<NodeOp>(op).getInput();
455 fieldRef = next.getSubField(fieldRef.getFieldID());
460 if (lookThroughCasts &&
461 isa<AsUIntPrimOp, AsSIntPrimOp, AsClockPrimOp, AsAsyncResetPrimOp>(
463 auto input = op->getOperand(0);
465 fieldRef = next.getSubField(fieldRef.getFieldID());
470 if (isa<PadPrimOp, TailPrimOp>(op)) {
471 auto input = op->getOperand(0);
473 fieldRef = next.getSubField(fieldRef.getFieldID());
482 if (!callback(original, fieldRef))
490 if (workStack.empty())
492 auto &back = workStack.back();
493 auto current = back.current;
495 if (back.it == current.user_end()) {
496 workStack.pop_back();
502 auto *user = *back.it++;
503 auto fieldID = back.fieldID;
505 if (
auto subfield = dyn_cast<SubfieldOp>(user)) {
506 BundleType bundleType = subfield.getInput().getType();
507 auto index = subfield.getFieldIndex();
508 auto subID = bundleType.getFieldID(index);
510 if (fieldID && index != bundleType.getIndexForFieldID(fieldID))
512 auto subRef = fieldRef.getSubField(subID);
513 auto subOriginal = original.getSubField(subID);
514 auto value = subfield.getResult();
517 workStack.emplace_back(subOriginal, subRef, value, 0);
520 workStack.emplace_back(subOriginal, subRef, value, fieldID - subID);
522 }
else if (
auto subindex = dyn_cast<SubindexOp>(user)) {
523 FVectorType vectorType = subindex.getInput().getType();
524 auto index = subindex.getIndex();
525 auto subID = vectorType.getFieldID(index);
527 if (fieldID && index != vectorType.getIndexForFieldID(fieldID))
529 auto subRef = fieldRef.getSubField(subID);
530 auto subOriginal = original.getSubField(subID);
531 auto value = subindex.getResult();
534 workStack.emplace_back(subOriginal, subRef, value, 0);
537 workStack.emplace_back(subOriginal, subRef, value, fieldID - subID);
539 }
else if (
auto connect = dyn_cast<FConnectLike>(user)) {
541 if (connect.getDest() != current)
559 if (LLVM_UNLIKELY(!value))
563 auto *op = value.getDefiningOp();
570 return TypeSwitch<Operation *, FieldRef>(op)
571 .Case<RefCastOp, ConstCastOp, UninferredResetCastOp>(
572 [lookThroughCasts](
auto op) {
573 if (!lookThroughCasts)
577 .Case<SubfieldOp, OpenSubfieldOp, SubindexOp, OpenSubindexOp, RefSubOp,
579 [](
auto subOp) {
return subOp.getAccessedField(); })
584 bool lookThroughCasts) {
585 if (LLVM_UNLIKELY(!value))
591 auto deltaRef =
getDeltaRef(value, lookThroughCasts);
595 id = deltaRef.getSubField(
id).getFieldID();
597 value = deltaRef.getValue();
602static void getDeclName(Value value, SmallString<64> &
string,
bool nameSafe) {
605 if (
auto arg = dyn_cast<BlockArgument>(value)) {
607 auto *op = arg.getOwner()->getParentOp();
608 TypeSwitch<Operation *>(op).Case<FModuleOp, ClassOp>([&](
auto op) {
609 auto name = cast<StringAttr>(op.getPortNames()[arg.getArgNumber()]);
610 string += name.getValue();
615 auto *op = value.getDefiningOp();
616 TypeSwitch<Operation *>(op)
617 .Case<ObjectOp>([&](ObjectOp op) {
618 string += op.getInstanceName();
621 .Case<InstanceOp, InstanceChoiceOp, MemOp>([&](
auto op) {
622 string += op.getName();
623 string += nameSafe ?
"_" :
".";
624 string += op.getPortName(cast<OpResult>(value).getResultNumber());
627 .Case<FNamableOp>([&](
auto op) {
628 string += op.getName();
631 .Case<mlir::UnrealizedConversionCastOp>(
632 [&](mlir::UnrealizedConversionCastOp cast) {
634 if (cast.getNumResults() == 1 && cast.getNumOperands() == 1 &&
635 cast.getResult(0).getType() == cast.getOperand(0).getType()) {
636 value = cast.getInputs()[0];
651std::pair<std::string, bool>
653 SmallString<64> name;
656 bool rootKnown = !name.empty();
658 auto type = value.getType();
662 if (
auto refTy = type_dyn_cast<RefType>(type))
663 type = refTy.getType();
665 if (
auto bundleType = type_dyn_cast<BundleType>(type)) {
666 auto index = bundleType.getIndexForFieldID(localID);
668 auto &element = bundleType.getElements()[index];
670 name += nameSafe ?
"_" :
".";
671 name += element.name.getValue();
674 localID = localID - bundleType.getFieldID(index);
675 }
else if (
auto bundleType = type_dyn_cast<OpenBundleType>(type)) {
676 auto index = bundleType.getIndexForFieldID(localID);
678 auto &element = bundleType.getElements()[index];
680 name += nameSafe ?
"_" :
".";
681 name += element.name.getValue();
684 localID = localID - bundleType.getFieldID(index);
685 }
else if (
auto vecType = type_dyn_cast<FVectorType>(type)) {
686 auto index = vecType.getIndexForFieldID(localID);
687 name += nameSafe ?
"_" :
"[";
688 name += std::to_string(index);
692 type = vecType.getElementType();
693 localID = localID - vecType.getFieldID(index);
694 }
else if (
auto vecType = type_dyn_cast<OpenVectorType>(type)) {
695 auto index = vecType.getIndexForFieldID(localID);
696 name += nameSafe ?
"_" :
"[";
697 name += std::to_string(index);
701 type = vecType.getElementType();
702 localID = localID - vecType.getFieldID(index);
703 }
else if (
auto classType = type_dyn_cast<ClassType>(type)) {
704 auto index = classType.getIndexForFieldID(localID);
705 auto &element = classType.getElement(index);
706 name += nameSafe ?
"_" :
".";
707 name += element.name.getValue();
709 localID = localID - classType.getFieldID(index);
715 llvm_unreachable(
"unsupported type");
719 return {name.str().str(), rootKnown};
727 Value value,
unsigned fieldID) {
729 while (fieldID != 0) {
731 .
Case<BundleType>([&](
auto bundle) {
732 auto index = bundle.getIndexForFieldID(fieldID);
733 value = SubfieldOp::create(builder, value, index);
734 fieldID -= bundle.getFieldID(index);
736 .Case<OpenBundleType>([&](
auto bundle) {
737 auto index = bundle.getIndexForFieldID(fieldID);
738 value = OpenSubfieldOp::create(builder, value, index);
739 fieldID -= bundle.getFieldID(index);
741 .Case<FVectorType>([&](
auto vector) {
742 auto index = vector.getIndexForFieldID(fieldID);
743 value = SubindexOp::create(builder, value, index);
744 fieldID -= vector.getFieldID(index);
746 .Case<OpenVectorType>([&](
auto vector) {
747 auto index = vector.getIndexForFieldID(fieldID);
748 value = OpenSubindexOp::create(builder, value, index);
749 fieldID -= vector.getFieldID(index);
751 .Case<RefType>([&](
auto reftype) {
753 .template Case<BundleType, FVectorType>([&](
auto type) {
754 auto index = type.getIndexForFieldID(fieldID);
755 value = RefSubOp::create(builder, value, index);
756 fieldID -= type.getFieldID(index);
758 .Default([&](
auto _) {
759 llvm::report_fatal_error(
760 "unrecognized type for indexing through with fieldID");
764 .Default([&](
auto _) {
765 llvm::report_fatal_error(
766 "unrecognized type for indexing through with fieldID");
786 return fn(0, type,
false);
788 uint64_t fieldID = 0;
789 auto recurse = [&](
auto &&f,
FIRRTLBaseType type,
bool isFlip) ->
void {
791 .
Case<BundleType>([&](BundleType bundle) {
792 for (
size_t i = 0, e = bundle.getNumElements(); i < e; ++i) {
794 f(f, bundle.getElementType(i),
795 isFlip ^ bundle.getElement(i).isFlip);
798 .
template Case<FVectorType>([&](FVectorType vector) {
799 for (
size_t i = 0, e = vector.getNumElements(); i < e; ++i) {
801 f(f, vector.getElementType(), isFlip);
804 .
template Case<FEnumType>([&](FEnumType fenum) {
808 fn(fieldID, fenum, isFlip);
811 assert(groundType.isGround() &&
812 "only ground types are expected here");
813 fn(fieldID, groundType, isFlip);
816 recurse(recurse, type,
false);
823 if (
auto arg = dyn_cast<BlockArgument>(root)) {
824 auto mod = cast<FModuleLike>(arg.getOwner()->getParentOp());
835 return TypeSwitch<Operation *, FieldRef>(ist.
getOp())
836 .Case<FModuleOp>([&](
auto fmod) {
842 auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(ist.
getOp());
843 assert(symOp && symOp.getTargetResultIndex() &&
844 (symOp.supportsPerFieldSymbols() || ist.
getField() == 0));
850 MLIRContext *
context, hw::InnerSymAttr attr, uint64_t fieldID,
852 SmallVector<hw::InnerSymPropertiesAttr> props;
855 if (
auto sym = attr.getSymIfExists(fieldID))
857 llvm::append_range(props, attr.getProps());
861 auto sym = StringAttr::get(
context, getNamespace().newName(
"sym"));
862 props.push_back(hw::InnerSymPropertiesAttr::get(
867 [](
auto &p,
auto &q) {
return p.getFieldID() < q.getFieldID(); });
868 return {hw::InnerSymAttr::get(
context, props), sym};
875 if (
auto mod = dyn_cast<FModuleLike>(target.
getOp())) {
876 auto portIdx = target.
getPort();
877 assert(portIdx < mod.getNumPorts());
881 mod.setPortSymbolAttr(portIdx, attr);
886 if (
auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(target.
getOp())) {
890 symOp.setInnerSymbolAttr(attr);
895 assert(0 &&
"target must be port of FModuleLike or InnerSymbol");
903 module = cast<FModuleLike>(target.getOp());
905 module = target.getOp()->getParentOfType<FModuleOp>();
909 return getNamespace(module);
918 auto mod = target.
isPort() ? dyn_cast<FModuleLike>(target.
getOp())
919 : target.
getOp()->getParentOfType<FModuleOp>();
921 "must be an operation inside an FModuleOp or port of FModuleLike");
922 return hw::InnerRefAttr::get(SymbolTable::getSymbolName(mod),
927std::pair<bool, std::optional<mlir::LocationAttr>>
929 StringAttr &locatorFilenameCache,
930 FileLineColLoc &fileLineColLocCache,
933 if (!spelling.starts_with(
"@[") || !spelling.ends_with(
"]"))
934 return {
false, std::nullopt};
936 spelling = spelling.drop_front(2).drop_back(1);
940 auto decodeLocator = [&](StringRef input,
unsigned &resultLineNo,
941 unsigned &resultColNo) -> StringRef {
943 auto spaceLoc = input.find_last_of(
' ');
944 if (spaceLoc == StringRef::npos)
947 auto filename = input.take_front(spaceLoc);
948 auto lineAndColumn = input.drop_front(spaceLoc + 1);
952 StringRef lineStr, colStr;
953 std::tie(lineStr, colStr) = lineAndColumn.split(
':');
956 if (lineStr.getAsInteger(10, resultLineNo))
958 if (!colStr.empty()) {
959 if (colStr.front() !=
'{') {
960 if (colStr.getAsInteger(10, resultColNo))
964 if (colStr.drop_front().split(
',').first.getAsInteger(10, resultColNo))
972 unsigned lineNo = 0, columnNo = 0;
973 StringRef filename = decodeLocator(spelling, lineNo, columnNo);
974 if (filename.empty())
975 return {
false, std::nullopt};
980 return {
true, std::nullopt};
984 auto getFileLineColLoc = [&](StringRef filename,
unsigned lineNo,
985 unsigned columnNo) -> FileLineColLoc {
987 StringAttr filenameId = locatorFilenameCache;
988 if (filenameId.str() != filename) {
990 locatorFilenameCache = filenameId = StringAttr::get(
context, filename);
994 return fileLineColLocCache =
995 FileLineColLoc::get(filenameId, lineNo, columnNo);
999 auto result = fileLineColLocCache;
1000 if (result && result.getLine() == lineNo && result.getColumn() == columnNo)
1003 return fileLineColLocCache =
1004 FileLineColLoc::get(filenameId, lineNo, columnNo);
1015 SmallVector<Location> extraLocs;
1016 auto spaceLoc = filename.find_last_of(
' ');
1017 while (spaceLoc != StringRef::npos) {
1020 unsigned nextLineNo = 0, nextColumnNo = 0;
1022 decodeLocator(filename.take_front(spaceLoc), nextLineNo, nextColumnNo);
1025 if (nextFilename.empty())
1031 getFileLineColLoc(filename.drop_front(spaceLoc + 1), lineNo, columnNo);
1032 extraLocs.push_back(loc);
1033 filename = nextFilename;
1034 lineNo = nextLineNo;
1035 columnNo = nextColumnNo;
1036 spaceLoc = filename.find_last_of(
' ');
1039 mlir::LocationAttr result = getFileLineColLoc(filename, lineNo, columnNo);
1040 if (!extraLocs.empty()) {
1041 extraLocs.push_back(result);
1042 std::reverse(extraLocs.begin(), extraLocs.end());
1043 result = FusedLoc::get(
context, extraLocs);
1045 return {
true, result};
1052 Type type, std::optional<Location> loc,
1053 llvm::function_ref<hw::TypeAliasType(Type, BaseTypeAliasType, Location)>
1055 auto firType = type_dyn_cast<FIRRTLBaseType>(type);
1061 if (BaseTypeAliasType aliasType = dyn_cast<BaseTypeAliasType>(firType)) {
1063 loc = UnknownLoc::get(type.getContext());
1064 type =
lowerType(aliasType.getInnerType(), loc, getTypeDeclFn);
1065 return getTypeDeclFn(type, aliasType, *loc);
1068 firType = firType.getPassiveType();
1070 if (
auto bundle = type_dyn_cast<BundleType>(firType)) {
1071 mlir::SmallVector<hw::StructType::FieldInfo, 8> hwfields;
1072 for (
auto element : bundle) {
1073 Type etype =
lowerType(element.type, loc, getTypeDeclFn);
1076 hwfields.push_back(hw::StructType::FieldInfo{element.name, etype});
1078 return hw::StructType::get(type.getContext(), hwfields);
1080 if (
auto vec = type_dyn_cast<FVectorType>(firType)) {
1081 auto elemTy =
lowerType(vec.getElementType(), loc, getTypeDeclFn);
1084 return hw::ArrayType::get(elemTy, vec.getNumElements());
1086 if (
auto fenum = type_dyn_cast<FEnumType>(firType)) {
1087 mlir::SmallVector<hw::UnionType::FieldInfo, 8> hwfields;
1089 for (
auto element : fenum) {
1090 Type etype =
lowerType(element.type, loc, getTypeDeclFn);
1093 hwfields.push_back(hw::UnionType::FieldInfo{element.name, etype, 0});
1094 if (element.type.getBitWidthOrSentinel() != 0)
1097 auto tagTy = IntegerType::get(type.getContext(), fenum.getTagWidth());
1100 auto bodyTy = hw::UnionType::get(type.getContext(), hwfields);
1101 hw::StructType::FieldInfo fields[2] = {
1102 {StringAttr::get(type.getContext(),
"tag"), tagTy},
1103 {StringAttr::get(type.getContext(),
"body"), bodyTy}};
1104 return hw::StructType::get(type.getContext(), fields);
1106 if (type_isa<ClockType>(firType))
1107 return seq::ClockType::get(firType.getContext());
1109 auto width = firType.getBitWidthOrSentinel();
1111 return IntegerType::get(type.getContext(), width);
1117 mlir::ImplicitLocOpBuilder &builderOM) {
1119 auto *
context = op->getContext();
1120 auto id = DistinctAttr::create(UnitAttr::get(
context));
1121 TargetKind kind = TargetKind::Reference;
1124 NamedAttrList fields;
1125 fields.append(
"id",
id);
1126 fields.append(
"class", StringAttr::get(
context,
"circt.tracker"));
1128 fields.append(
"circt.nonlocal", mlir::FlatSymbolRefAttr::get(nla));
1132 if (isa<InstanceOp, FModuleLike>(op))
1133 kind = TargetKind::Instance;
1137 return PathOp::create(builderOM, kind,
id);
1146 llvm::StringRef formatString,
1147 llvm::ArrayRef<mlir::Value> specOperands,
1148 mlir::StringAttr &formatStringResult,
1149 llvm::SmallVectorImpl<mlir::Value> &operands) {
1152 llvm::SmallString<64> validatedFormatString;
1154 for (
size_t i = 0, e = formatString.size(), opIdx = 0; i != e; ++i) {
1155 auto c = formatString[i];
1160 validatedFormatString.push_back(c);
1163 llvm::SmallString<6> width;
1164 c = formatString[++i];
1167 c = formatString[++i];
1174 return mlir::emitError(loc) <<
"ASCII character format specifiers "
1175 "('%c') may not specify a width";
1181 validatedFormatString.append(width);
1182 if (specOperands.size() <= opIdx)
1183 return mlir::emitError(loc) <<
"not enough operands for format "
1185 operands.push_back(specOperands[opIdx++]);
1189 return mlir::emitError(loc)
1190 <<
"literal percents ('%%') may not specify a width";
1194 return mlir::emitError(loc)
1195 <<
"unknown printf substitution '%" << width << c <<
"'";
1197 validatedFormatString.push_back(c);
1205 if (formatString[i + 1] !=
'{') {
1206 validatedFormatString.push_back(c);
1212 while (formatString[i] !=
'}')
1214 if (formatString[i] !=
'}')
1215 return mlir::emitError(loc)
1216 <<
"expected '}' to terminate special substitution";
1218 auto specialString = formatString.slice(start, i);
1219 if (specialString ==
"SimulationTime") {
1220 operands.push_back(TimeOp::create(builder, loc));
1221 }
else if (specialString ==
"HierarchicalModuleName") {
1222 operands.push_back(HierarchicalModuleNameOp::create(builder, loc));
1224 return mlir::emitError(loc)
1225 <<
"unknown printf substitution '" << specialString
1226 <<
"' (did you misspell it?)";
1229 validatedFormatString.append(
"{{}}");
1234 validatedFormatString.push_back(c);
1238 formatStringResult = builder.getStringAttr(validatedFormatString);
1239 return mlir::success();
1247 Operation *operation) {
1248 if (
auto mod = dyn_cast<mlir::ModuleOp>(operation))
1249 for (
auto &op : *mod.getBody())
1250 if ((operation = dyn_cast<CircuitOp>(&op)))
1253 for (
auto option : cast<CircuitOp>(operation).getOps<OptionOp>())
1254 for (
auto optionCase : option.getOps<OptionCaseOp>())
1255 cache[{option.getSymNameAttr(), optionCase.getSymNameAttr()}] =
1256 optionCase.getCaseMacroAttr();
1261 StringAttr caseName)
const {
1262 auto it = cache.find({optionName, caseName});
1263 if (it == cache.end())
assert(baseType &&"element must be base type")
MlirType uint64_t numElements
static std::unique_ptr< Context > context
static LogicalResult connectIfAggregates(ImplicitLocOpBuilder &builder, Value dst, FIRRTLType dstFType, Value src, FIRRTLType srcFType, llvm::function_ref< Location()> getDiagLoc, bool warnOnTruncation)
static void getDeclName(Value value, SmallString< 64 > &string, bool nameSafe)
Get the string name of a value which is a direct child of a declaration op.
static Value lookThroughWires(Value value)
Trace a value through wires to its original definition.
This class represents a reference to a specific field or element of an aggregate value.
unsigned getFieldID() const
Get the field ID of this FieldRef, which is a unique identifier mapped to a specific field in a bundl...
Value getValue() const
Get the Value which created this location.
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
bool applyToOperation(Operation *op) const
Store the annotations in this set in an operation's annotations attribute, overwriting any existing a...
void addAnnotations(ArrayRef< Annotation > annotations)
Add more annotations to this annotation set.
bool isConst() const
Returns true if this is a 'const' type that can only hold compile-time constant values.
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.
FlatSymbolRefAttr getMacro(StringAttr optionName, StringAttr caseName) const
InstanceChoiceMacroTable(Operation *op)
This is the common base class between SIntType and UIntType.
IntType getConstType(bool isConst) const
Return a 'const' or non-'const' version of this type.
ImplicitLocOpBuilder & builder
SmallDenseMap< Type, Value, 8 > cache
Value getUnknown(PropertyType type)
Get or create an UnknownValueOp for the given property type.
The target of an inner symbol, the entity the symbol is a handle for.
auto getField() const
Return the target's fieldID.
auto getPort() const
Return the target's port, if valid. Check "isPort()".
bool isPort() const
Return if this targets a port.
Operation * getOp() const
Return the target's base operation. For ports, this is the module.
llvm::function_ref< hw::InnerSymbolNamespace &(FModuleLike mod)> GetNamespaceCallback
FieldRef getFieldRefForTarget(const hw::InnerSymTarget &ist)
Get FieldRef pointing to the specified inner symbol target, which must be valid.
FieldRef getDeltaRef(Value value, bool lookThroughCasts=false)
Get the delta indexing from a value, as a FieldRef.
FIRRTLBaseType getBaseType(Type type)
If it is a base type, return it as is.
FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts=false)
Get the FieldRef from a value.
mlir::TypedValue< FIRRTLBaseType > FIRRTLBaseValue
void walkGroundTypes(FIRRTLType firrtlType, llvm::function_ref< void(uint64_t, FIRRTLBaseType, bool)> fn)
Walk leaf ground types in the firrtlType and apply the function fn.
PathOp createPathRef(Operation *op, hw::HierPathOp nla, mlir::ImplicitLocOpBuilder &builderOM)
Add the tracker annotation to the op and get a PathOp to the op.
IntegerAttr getIntAttr(Type type, const APInt &value)
Utiility for generating a constant attribute.
std::pair< bool, std::optional< mlir::LocationAttr > > maybeStringToLocation(llvm::StringRef spelling, bool skipParsing, mlir::StringAttr &locatorFilenameCache, FileLineColLoc &fileLineColLocCache, MLIRContext *context)
std::pair< hw::InnerSymAttr, StringAttr > getOrAddInnerSym(MLIRContext *context, hw::InnerSymAttr attr, uint64_t fieldID, llvm::function_ref< hw::InnerSymbolNamespace &()> getNamespace)
Ensure that the the InnerSymAttr has a symbol on the field specified.
hw::InnerRefAttr getInnerRefTo(const hw::InnerSymTarget &target, GetNamespaceCallback getNamespace)
Obtain an inner reference to the target (operation or port), adding an inner symbol as necessary.
void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs, bool warnOnTruncation=false)
Emit a connect between two values.
PropAssignOp getPropertyAssignment(FIRRTLPropertyValue value)
Return the single assignment to a Property value.
mlir::ParseResult parseFormatString(mlir::OpBuilder &builder, mlir::Location loc, llvm::StringRef formatString, llvm::ArrayRef< mlir::Value > specOperands, mlir::StringAttr &formatStringResult, llvm::SmallVectorImpl< mlir::Value > &operands)
Value getModuleScopedDriver(Value val, bool lookThroughWires, bool lookThroughNodes, bool lookThroughCasts)
Return the value that drives another FIRRTL value within module scope.
bool preservesInitial(IntegerAttr initial, std::optional< APInt > foldedValue=std::nullopt)
Return true if replacing a register carrying the time-zero initial value with foldedValue does not ch...
Value getDriverFromConnect(Value val)
Return the module-scoped driver of a value only looking through one connect.
Value getValueByFieldID(ImplicitLocOpBuilder builder, Value value, unsigned fieldID)
This gets the value targeted by a field id.
std::pair< std::string, bool > getFieldName(const FieldRef &fieldRef, bool nameSafe=false)
Get a string identifier representing the FieldRef.
llvm::function_ref< bool(const FieldRef &dst, const FieldRef &src)> WalkDriverCallback
Walk all the drivers of a value, passing in the connect operations drive the value.
mlir::TypedValue< PropertyType > FIRRTLPropertyValue
Type lowerType(Type type, std::optional< Location > loc={}, llvm::function_ref< hw::TypeAliasType(Type, BaseTypeAliasType, Location)> getTypeDeclFn={})
Given a type, return the corresponding lowered type for the HW dialect.
hw::InnerSymTarget getTargetFor(FieldRef ref)
Return the inner sym target for the specified value and fieldID.
bool areTypesConstCastable(FIRRTLType destType, FIRRTLType srcType, bool srcOuterTypeIsConst=false)
Returns whether the srcType can be const-casted to the destType.
bool walkDrivers(FIRRTLBaseValue value, bool lookThroughWires, bool lookThroughNodes, bool lookThroughCasts, WalkDriverCallback callback)
IntegerAttr getIntOnesAttr(Type type)
Utility for generating a constant all ones attribute.
IntegerAttr getIntZerosAttr(Type type)
Utility for generating a constant zero attribute.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.