19#include "mlir/IR/ImplicitLocOpBuilder.h"
20#include "llvm/ADT/SmallString.h"
21#include "llvm/ADT/TypeSwitch.h"
22#include "llvm/Support/Path.h"
25using namespace firrtl;
32 Value &cached =
cache[type];
34 cached =
builder.create<UnknownValueOp>(type);
44 ImplicitLocOpBuilder locBuilder(loc, builder.getInsertionBlock(),
45 builder.getInsertionPoint());
47 builder.restoreInsertionPoint(locBuilder.saveInsertionPoint());
50template <
typename ATy,
typename IndexOp,
bool isBundle >
54 auto dstAggTy = type_dyn_cast<ATy>(dstFType);
57 auto srcAggTy = type_dyn_cast<ATy>(srcFType);
66 ConnectOp::create(builder, dst, src);
71 auto dstField = IndexOp::create(builder, dst, i);
72 auto srcField = IndexOp::create(builder, src, i);
73 if constexpr (isBundle) {
74 if (dstAggTy.getElement(i).isFlip)
75 std::swap(dstField, srcField);
86 auto dstFType = type_cast<FIRRTLType>(dst.getType());
87 auto srcFType = type_cast<FIRRTLType>(src.getType());
88 auto dstType = type_dyn_cast<FIRRTLBaseType>(dstFType);
89 auto srcType = type_dyn_cast<FIRRTLBaseType>(srcFType);
93 if (type_isa<RefType>(dstFType)) {
94 if (dstFType != srcFType)
95 src = RefCastOp::create(builder, dstFType, src);
96 RefDefineOp::create(builder, dst, src);
97 }
else if (type_isa<PropertyType>(dstFType) &&
98 type_isa<PropertyType>(srcFType)) {
100 PropAssignOp::create(builder, dst, src);
101 }
else if (type_isa<DomainType>(dstFType) &&
102 type_isa<DomainType>(srcFType)) {
103 DomainDefineOp::create(builder, dst, src);
104 }
else if (failed(connectIfAggregates<OpenBundleType, OpenSubfieldOp, true>(
105 builder, dst, dstFType, src, srcFType)) &&
107 connectIfAggregates<OpenVectorType, OpenSubindexOp, false>(
108 builder, dst, dstFType, src, srcFType))) {
110 ConnectOp::create(builder, dst, src);
116 if (isa<AnalogType>(dstType)) {
117 AttachOp::create(builder, ArrayRef{dst, src});
122 if (dstType == srcType && dstType.isPassive() &&
123 !dstType.hasUninferredWidth() && !dstType.containsAnalog()) {
124 MatchingConnectOp::create(builder, dst, src);
128 if (succeeded(connectIfAggregates<BundleType, SubfieldOp, true>(
129 builder, dst, dstFType, src, srcFType)) ||
130 succeeded(connectIfAggregates<FVectorType, SubindexOp, false>(
131 builder, dst, dstFType, src, srcFType)))
134 if ((dstType.hasUninferredReset() || srcType.hasUninferredReset()) &&
135 dstType != srcType) {
136 srcType = dstType.getConstType(srcType.isConst());
137 src = UninferredResetCastOp::create(builder, srcType, src);
141 auto dstWidth = dstType.getBitWidthOrSentinel();
142 auto srcWidth = srcType.getBitWidthOrSentinel();
143 if (dstWidth < 0 || srcWidth < 0) {
150 if (dstType != srcType && dstType.getWidthlessType() != srcType &&
152 src = ConstCastOp::create(builder, dstType.getWidthlessType(), src);
155 ConnectOp::create(builder, dst, src);
160 if (dstWidth < srcWidth) {
163 type_cast<IntType>(dstType).
getConstType(srcType.isConst());
164 bool isSignedDest = tmpType.
isSigned();
167 UIntType::get(dstType.getContext(), dstWidth, srcType.isConst());
168 src = TailPrimOp::create(builder, tmpType, src, srcWidth - dstWidth);
171 src = AsSIntPrimOp::create(builder,
172 dstType.getConstType(tmpType.
isConst()), src);
173 }
else if (srcWidth < dstWidth) {
175 src = PadPrimOp::create(builder, src, dstWidth);
178 if (
auto srcType = type_cast<FIRRTLBaseType>(src.getType());
179 srcType && dstType != srcType &&
181 src = ConstCastOp::create(builder, dstType, src);
186 if (dstType == src.getType() && dstType.isPassive() &&
187 !dstType.hasUninferredWidth()) {
188 MatchingConnectOp::create(builder, dst, src);
190 ConnectOp::create(builder, dst, src);
194 auto intType = type_cast<IntType>(type);
195 assert((!intType.hasWidth() ||
196 (
unsigned)intType.getWidthOrSentinel() == value.getBitWidth()) &&
197 "value / type width mismatch");
199 intType.isSigned() ? IntegerType::Signed : IntegerType::Unsigned;
201 IntegerType::get(type.getContext(), value.getBitWidth(), intSign);
202 return IntegerAttr::get(attrType, value);
208 int32_t width = abs(type_cast<IntType>(type).getWidthOrSentinel());
215 int32_t width = abs(type_cast<IntType>(type).getWidthOrSentinel());
217 type, APInt(width, -1,
false,
true));
223 for (
auto *user : value.getUsers())
224 if (
auto propassign = dyn_cast<PropAssignOp>(user))
225 if (propassign.getDest() == value)
240 for (
auto *user : val.getUsers()) {
241 if (
auto connect = dyn_cast<FConnectLike>(user)) {
242 if (connect.getDest() != val)
244 return connect.getSrc();
251 bool lookThroughNodes,
252 bool lookThroughCasts) {
257 auto updateVal = [&](Value thisVal) {
258 for (
auto *user : thisVal.getUsers()) {
259 if (
auto connect = dyn_cast<FConnectLike>(user)) {
260 if (connect.getDest() != val)
262 val = connect.getSrc();
272 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
273 FModuleOp op = cast<FModuleOp>(val.getParentBlock()->getParentOp());
274 auto direction = op.getPortDirection(blockArg.getArgNumber());
282 auto *op = val.getDefiningOp();
285 if (
auto inst = dyn_cast<InstanceOp>(op)) {
286 auto resultNo = cast<OpResult>(val).getResultNumber();
289 return inst.getResult(resultNo);
296 updateVal(op->getResult(0));
301 if (lookThroughNodes && isa<NodeOp>(op)) {
302 val = cast<NodeOp>(op).getInput();
306 if (lookThroughCasts &&
307 isa<AsUIntPrimOp, AsSIntPrimOp, AsClockPrimOp, AsAsyncResetPrimOp>(
309 val = op->getOperand(0);
314 if (isa<PadPrimOp, TailPrimOp>(op)) {
315 val = op->getOperand(0);
330 bool lookThroughNodes,
bool lookThroughCasts,
334 assert(value.getType().isPassive() &&
"this code was not tested with flips");
345 struct StackElement {
347 : dst(dst), src(src), current(current), it(current.user_begin()),
360 Value::user_iterator it;
364 SmallVector<StackElement> workStack;
370 auto value = src.getValue();
371 workStack.emplace_back(dst, src, value, src.
getFieldID());
377 auto fieldRef = original;
385 auto val = fieldRef.getValue();
388 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
389 auto *parent = val.getParentBlock()->getParentOp();
390 auto module = cast<FModuleLike>(parent);
391 auto direction =
module.getPortDirection(blockArg.getArgNumber());
394 if (!callback(original, fieldRef))
398 addToWorklist(original, fieldRef);
402 auto *op = val.getDefiningOp();
405 if (
auto inst = dyn_cast<InstanceOp>(op)) {
406 auto resultNo = cast<OpResult>(val).getResultNumber();
409 if (!callback(original, fieldRef))
413 addToWorklist(original, fieldRef);
419 addToWorklist(original, fieldRef);
424 if (lookThroughNodes && isa<NodeOp>(op)) {
425 auto input = cast<NodeOp>(op).getInput();
427 fieldRef = next.getSubField(fieldRef.getFieldID());
432 if (lookThroughCasts &&
433 isa<AsUIntPrimOp, AsSIntPrimOp, AsClockPrimOp, AsAsyncResetPrimOp>(
435 auto input = op->getOperand(0);
437 fieldRef = next.getSubField(fieldRef.getFieldID());
442 if (isa<PadPrimOp, TailPrimOp>(op)) {
443 auto input = op->getOperand(0);
445 fieldRef = next.getSubField(fieldRef.getFieldID());
454 if (!callback(original, fieldRef))
462 if (workStack.empty())
464 auto &back = workStack.back();
465 auto current = back.current;
467 if (back.it == current.user_end()) {
468 workStack.pop_back();
474 auto *user = *back.it++;
475 auto fieldID = back.fieldID;
477 if (
auto subfield = dyn_cast<SubfieldOp>(user)) {
478 BundleType bundleType = subfield.getInput().getType();
479 auto index = subfield.getFieldIndex();
480 auto subID = bundleType.getFieldID(index);
482 if (fieldID && index != bundleType.getIndexForFieldID(fieldID))
484 auto subRef = fieldRef.getSubField(subID);
485 auto subOriginal = original.getSubField(subID);
486 auto value = subfield.getResult();
489 workStack.emplace_back(subOriginal, subRef, value, 0);
492 workStack.emplace_back(subOriginal, subRef, value, fieldID - subID);
494 }
else if (
auto subindex = dyn_cast<SubindexOp>(user)) {
495 FVectorType vectorType = subindex.getInput().getType();
496 auto index = subindex.getIndex();
497 auto subID = vectorType.getFieldID(index);
499 if (fieldID && index != vectorType.getIndexForFieldID(fieldID))
501 auto subRef = fieldRef.getSubField(subID);
502 auto subOriginal = original.getSubField(subID);
503 auto value = subindex.getResult();
506 workStack.emplace_back(subOriginal, subRef, value, 0);
509 workStack.emplace_back(subOriginal, subRef, value, fieldID - subID);
511 }
else if (
auto connect = dyn_cast<FConnectLike>(user)) {
513 if (connect.getDest() != current)
531 if (LLVM_UNLIKELY(!value))
535 auto *op = value.getDefiningOp();
542 return TypeSwitch<Operation *, FieldRef>(op)
543 .Case<RefCastOp, ConstCastOp, UninferredResetCastOp>(
544 [lookThroughCasts](
auto op) {
545 if (!lookThroughCasts)
549 .Case<SubfieldOp, OpenSubfieldOp, SubindexOp, OpenSubindexOp, RefSubOp,
551 [](
auto subOp) {
return subOp.getAccessedField(); })
556 bool lookThroughCasts) {
557 if (LLVM_UNLIKELY(!value))
563 auto deltaRef =
getDeltaRef(value, lookThroughCasts);
567 id = deltaRef.getSubField(
id).getFieldID();
569 value = deltaRef.getValue();
574static void getDeclName(Value value, SmallString<64> &
string,
bool nameSafe) {
577 if (
auto arg = dyn_cast<BlockArgument>(value)) {
579 auto *op = arg.getOwner()->getParentOp();
580 TypeSwitch<Operation *>(op).Case<FModuleOp, ClassOp>([&](
auto op) {
581 auto name = cast<StringAttr>(op.getPortNames()[arg.getArgNumber()]);
582 string += name.getValue();
587 auto *op = value.getDefiningOp();
588 TypeSwitch<Operation *>(op)
589 .Case<ObjectOp>([&](ObjectOp op) {
590 string += op.getInstanceName();
593 .Case<InstanceOp, InstanceChoiceOp, MemOp>([&](
auto op) {
594 string += op.getName();
595 string += nameSafe ?
"_" :
".";
596 string += op.getPortName(cast<OpResult>(value).getResultNumber());
599 .Case<FNamableOp>([&](
auto op) {
600 string += op.getName();
603 .Case<mlir::UnrealizedConversionCastOp>(
604 [&](mlir::UnrealizedConversionCastOp cast) {
606 if (cast.getNumResults() == 1 && cast.getNumOperands() == 1 &&
607 cast.getResult(0).getType() == cast.getOperand(0).getType()) {
608 value = cast.getInputs()[0];
623std::pair<std::string, bool>
625 SmallString<64> name;
628 bool rootKnown = !name.empty();
630 auto type = value.getType();
634 if (
auto refTy = type_dyn_cast<RefType>(type))
635 type = refTy.getType();
637 if (
auto bundleType = type_dyn_cast<BundleType>(type)) {
638 auto index = bundleType.getIndexForFieldID(localID);
640 auto &element = bundleType.getElements()[index];
642 name += nameSafe ?
"_" :
".";
643 name += element.name.getValue();
646 localID = localID - bundleType.getFieldID(index);
647 }
else if (
auto bundleType = type_dyn_cast<OpenBundleType>(type)) {
648 auto index = bundleType.getIndexForFieldID(localID);
650 auto &element = bundleType.getElements()[index];
652 name += nameSafe ?
"_" :
".";
653 name += element.name.getValue();
656 localID = localID - bundleType.getFieldID(index);
657 }
else if (
auto vecType = type_dyn_cast<FVectorType>(type)) {
658 auto index = vecType.getIndexForFieldID(localID);
659 name += nameSafe ?
"_" :
"[";
660 name += std::to_string(index);
664 type = vecType.getElementType();
665 localID = localID - vecType.getFieldID(index);
666 }
else if (
auto vecType = type_dyn_cast<OpenVectorType>(type)) {
667 auto index = vecType.getIndexForFieldID(localID);
668 name += nameSafe ?
"_" :
"[";
669 name += std::to_string(index);
673 type = vecType.getElementType();
674 localID = localID - vecType.getFieldID(index);
675 }
else if (
auto classType = type_dyn_cast<ClassType>(type)) {
676 auto index = classType.getIndexForFieldID(localID);
677 auto &element = classType.getElement(index);
678 name += nameSafe ?
"_" :
".";
679 name += element.name.getValue();
681 localID = localID - classType.getFieldID(index);
687 llvm_unreachable(
"unsupported type");
691 return {name.str().str(), rootKnown};
699 Value value,
unsigned fieldID) {
701 while (fieldID != 0) {
703 .
Case<BundleType>([&](
auto bundle) {
704 auto index = bundle.getIndexForFieldID(fieldID);
705 value = SubfieldOp::create(builder, value, index);
706 fieldID -= bundle.getFieldID(index);
708 .Case<OpenBundleType>([&](
auto bundle) {
709 auto index = bundle.getIndexForFieldID(fieldID);
710 value = OpenSubfieldOp::create(builder, value, index);
711 fieldID -= bundle.getFieldID(index);
713 .Case<FVectorType>([&](
auto vector) {
714 auto index = vector.getIndexForFieldID(fieldID);
715 value = SubindexOp::create(builder, value, index);
716 fieldID -= vector.getFieldID(index);
718 .Case<OpenVectorType>([&](
auto vector) {
719 auto index = vector.getIndexForFieldID(fieldID);
720 value = OpenSubindexOp::create(builder, value, index);
721 fieldID -= vector.getFieldID(index);
723 .Case<RefType>([&](
auto reftype) {
725 .template Case<BundleType, FVectorType>([&](
auto type) {
726 auto index = type.getIndexForFieldID(fieldID);
727 value = RefSubOp::create(builder, value, index);
728 fieldID -= type.getFieldID(index);
730 .Default([&](
auto _) {
731 llvm::report_fatal_error(
732 "unrecognized type for indexing through with fieldID");
736 .Default([&](
auto _) {
737 llvm::report_fatal_error(
738 "unrecognized type for indexing through with fieldID");
758 return fn(0, type,
false);
760 uint64_t fieldID = 0;
761 auto recurse = [&](
auto &&f,
FIRRTLBaseType type,
bool isFlip) ->
void {
763 .
Case<BundleType>([&](BundleType bundle) {
764 for (
size_t i = 0, e = bundle.getNumElements(); i < e; ++i) {
766 f(f, bundle.getElementType(i),
767 isFlip ^ bundle.getElement(i).isFlip);
770 .
template Case<FVectorType>([&](FVectorType vector) {
771 for (
size_t i = 0, e = vector.getNumElements(); i < e; ++i) {
773 f(f, vector.getElementType(), isFlip);
776 .
template Case<FEnumType>([&](FEnumType fenum) {
780 fn(fieldID, fenum, isFlip);
783 assert(groundType.isGround() &&
784 "only ground types are expected here");
785 fn(fieldID, groundType, isFlip);
788 recurse(recurse, type,
false);
795 if (
auto arg = dyn_cast<BlockArgument>(root)) {
796 auto mod = cast<FModuleLike>(arg.getOwner()->getParentOp());
807 return TypeSwitch<Operation *, FieldRef>(ist.
getOp())
808 .Case<FModuleOp>([&](
auto fmod) {
814 auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(ist.
getOp());
815 assert(symOp && symOp.getTargetResultIndex() &&
816 (symOp.supportsPerFieldSymbols() || ist.
getField() == 0));
822 MLIRContext *
context, hw::InnerSymAttr attr, uint64_t fieldID,
824 SmallVector<hw::InnerSymPropertiesAttr> props;
827 if (
auto sym = attr.getSymIfExists(fieldID))
829 llvm::append_range(props, attr.getProps());
833 auto sym = StringAttr::get(
context, getNamespace().newName(
"sym"));
834 props.push_back(hw::InnerSymPropertiesAttr::get(
839 [](
auto &p,
auto &q) {
return p.getFieldID() < q.getFieldID(); });
840 return {hw::InnerSymAttr::get(
context, props), sym};
847 if (
auto mod = dyn_cast<FModuleLike>(target.
getOp())) {
848 auto portIdx = target.
getPort();
849 assert(portIdx < mod.getNumPorts());
853 mod.setPortSymbolAttr(portIdx, attr);
858 if (
auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(target.
getOp())) {
862 symOp.setInnerSymbolAttr(attr);
867 assert(0 &&
"target must be port of FModuleLike or InnerSymbol");
875 module = cast<FModuleLike>(target.getOp());
877 module = target.getOp()->getParentOfType<FModuleOp>();
881 return getNamespace(module);
890 auto mod = target.
isPort() ? dyn_cast<FModuleLike>(target.
getOp())
891 : target.
getOp()->getParentOfType<FModuleOp>();
893 "must be an operation inside an FModuleOp or port of FModuleLike");
894 return hw::InnerRefAttr::get(SymbolTable::getSymbolName(mod),
899std::pair<bool, std::optional<mlir::LocationAttr>>
901 StringAttr &locatorFilenameCache,
902 FileLineColLoc &fileLineColLocCache,
905 if (!spelling.starts_with(
"@[") || !spelling.ends_with(
"]"))
906 return {
false, std::nullopt};
908 spelling = spelling.drop_front(2).drop_back(1);
912 auto decodeLocator = [&](StringRef input,
unsigned &resultLineNo,
913 unsigned &resultColNo) -> StringRef {
915 auto spaceLoc = input.find_last_of(
' ');
916 if (spaceLoc == StringRef::npos)
919 auto filename = input.take_front(spaceLoc);
920 auto lineAndColumn = input.drop_front(spaceLoc + 1);
924 StringRef lineStr, colStr;
925 std::tie(lineStr, colStr) = lineAndColumn.split(
':');
928 if (lineStr.getAsInteger(10, resultLineNo))
930 if (!colStr.empty()) {
931 if (colStr.front() !=
'{') {
932 if (colStr.getAsInteger(10, resultColNo))
936 if (colStr.drop_front().split(
',').first.getAsInteger(10, resultColNo))
944 unsigned lineNo = 0, columnNo = 0;
945 StringRef filename = decodeLocator(spelling, lineNo, columnNo);
946 if (filename.empty())
947 return {
false, std::nullopt};
952 return {
true, std::nullopt};
956 auto getFileLineColLoc = [&](StringRef filename,
unsigned lineNo,
957 unsigned columnNo) -> FileLineColLoc {
959 StringAttr filenameId = locatorFilenameCache;
960 if (filenameId.str() != filename) {
962 locatorFilenameCache = filenameId = StringAttr::get(
context, filename);
966 return fileLineColLocCache =
967 FileLineColLoc::get(filenameId, lineNo, columnNo);
971 auto result = fileLineColLocCache;
972 if (result && result.getLine() == lineNo && result.getColumn() == columnNo)
975 return fileLineColLocCache =
976 FileLineColLoc::get(filenameId, lineNo, columnNo);
987 SmallVector<Location> extraLocs;
988 auto spaceLoc = filename.find_last_of(
' ');
989 while (spaceLoc != StringRef::npos) {
992 unsigned nextLineNo = 0, nextColumnNo = 0;
994 decodeLocator(filename.take_front(spaceLoc), nextLineNo, nextColumnNo);
997 if (nextFilename.empty())
1003 getFileLineColLoc(filename.drop_front(spaceLoc + 1), lineNo, columnNo);
1004 extraLocs.push_back(loc);
1005 filename = nextFilename;
1006 lineNo = nextLineNo;
1007 columnNo = nextColumnNo;
1008 spaceLoc = filename.find_last_of(
' ');
1011 mlir::LocationAttr result = getFileLineColLoc(filename, lineNo, columnNo);
1012 if (!extraLocs.empty()) {
1013 extraLocs.push_back(result);
1014 std::reverse(extraLocs.begin(), extraLocs.end());
1015 result = FusedLoc::get(
context, extraLocs);
1017 return {
true, result};
1024 Type type, std::optional<Location> loc,
1025 llvm::function_ref<hw::TypeAliasType(Type, BaseTypeAliasType, Location)>
1027 auto firType = type_dyn_cast<FIRRTLBaseType>(type);
1033 if (BaseTypeAliasType aliasType = dyn_cast<BaseTypeAliasType>(firType)) {
1035 loc = UnknownLoc::get(type.getContext());
1036 type =
lowerType(aliasType.getInnerType(), loc, getTypeDeclFn);
1037 return getTypeDeclFn(type, aliasType, *loc);
1040 firType = firType.getPassiveType();
1042 if (
auto bundle = type_dyn_cast<BundleType>(firType)) {
1043 mlir::SmallVector<hw::StructType::FieldInfo, 8> hwfields;
1044 for (
auto element : bundle) {
1045 Type etype =
lowerType(element.type, loc, getTypeDeclFn);
1048 hwfields.push_back(hw::StructType::FieldInfo{element.name, etype});
1050 return hw::StructType::get(type.getContext(), hwfields);
1052 if (
auto vec = type_dyn_cast<FVectorType>(firType)) {
1053 auto elemTy =
lowerType(vec.getElementType(), loc, getTypeDeclFn);
1056 return hw::ArrayType::get(elemTy, vec.getNumElements());
1058 if (
auto fenum = type_dyn_cast<FEnumType>(firType)) {
1059 mlir::SmallVector<hw::UnionType::FieldInfo, 8> hwfields;
1061 for (
auto element : fenum) {
1062 Type etype =
lowerType(element.type, loc, getTypeDeclFn);
1065 hwfields.push_back(hw::UnionType::FieldInfo{element.name, etype, 0});
1066 if (element.type.getBitWidthOrSentinel() != 0)
1069 auto tagTy = IntegerType::get(type.getContext(), fenum.getTagWidth());
1072 auto bodyTy = hw::UnionType::get(type.getContext(), hwfields);
1073 hw::StructType::FieldInfo fields[2] = {
1074 {StringAttr::get(type.getContext(),
"tag"), tagTy},
1075 {StringAttr::get(type.getContext(),
"body"), bodyTy}};
1076 return hw::StructType::get(type.getContext(), fields);
1078 if (type_isa<ClockType>(firType))
1079 return seq::ClockType::get(firType.getContext());
1081 auto width = firType.getBitWidthOrSentinel();
1083 return IntegerType::get(type.getContext(), width);
1091 size_t e = std::min(a.size(), b.size());
1098 auto sep = llvm::sys::path::get_separator();
1099 while (!a.empty() && !a.ends_with(sep))
1104 mlir::ImplicitLocOpBuilder &builderOM) {
1106 auto *
context = op->getContext();
1107 auto id = DistinctAttr::create(UnitAttr::get(
context));
1108 TargetKind kind = TargetKind::Reference;
1111 NamedAttrList fields;
1112 fields.append(
"id",
id);
1113 fields.append(
"class", StringAttr::get(
context,
"circt.tracker"));
1115 fields.append(
"circt.nonlocal", mlir::FlatSymbolRefAttr::get(nla));
1119 if (isa<InstanceOp, FModuleLike>(op))
1120 kind = TargetKind::Instance;
1124 return PathOp::create(builderOM, kind,
id);
1133 llvm::StringRef formatString,
1134 llvm::ArrayRef<mlir::Value> specOperands,
1135 mlir::StringAttr &formatStringResult,
1136 llvm::SmallVectorImpl<mlir::Value> &operands) {
1139 llvm::SmallString<64> validatedFormatString;
1141 for (
size_t i = 0, e = formatString.size(), opIdx = 0; i != e; ++i) {
1142 auto c = formatString[i];
1147 validatedFormatString.push_back(c);
1150 llvm::SmallString<6> width;
1151 c = formatString[++i];
1154 c = formatString[++i];
1161 return mlir::emitError(loc) <<
"ASCII character format specifiers "
1162 "('%c') may not specify a width";
1168 validatedFormatString.append(width);
1169 if (specOperands.size() <= opIdx)
1170 return mlir::emitError(loc) <<
"not enough operands for format "
1172 operands.push_back(specOperands[opIdx++]);
1176 return mlir::emitError(loc)
1177 <<
"literal percents ('%%') may not specify a width";
1181 return mlir::emitError(loc)
1182 <<
"unknown printf substitution '%" << width << c <<
"'";
1184 validatedFormatString.push_back(c);
1192 if (formatString[i + 1] !=
'{') {
1193 validatedFormatString.push_back(c);
1199 while (formatString[i] !=
'}')
1201 if (formatString[i] !=
'}')
1202 return mlir::emitError(loc)
1203 <<
"expected '}' to terminate special substitution";
1205 auto specialString = formatString.slice(start, i);
1206 if (specialString ==
"SimulationTime") {
1207 operands.push_back(TimeOp::create(builder, loc));
1208 }
else if (specialString ==
"HierarchicalModuleName") {
1209 operands.push_back(HierarchicalModuleNameOp::create(builder, loc));
1211 return mlir::emitError(loc)
1212 <<
"unknown printf substitution '" << specialString
1213 <<
"' (did you misspell it?)";
1216 validatedFormatString.append(
"{{}}");
1221 validatedFormatString.push_back(c);
1225 formatStringResult = builder.getStringAttr(validatedFormatString);
1226 return mlir::success();
1234 Operation *operation) {
1235 if (
auto mod = dyn_cast<mlir::ModuleOp>(operation))
1236 for (
auto &op : *mod.getBody())
1237 if ((operation = dyn_cast<CircuitOp>(&op)))
1240 for (
auto option : cast<CircuitOp>(operation).getOps<OptionOp>())
1241 for (
auto optionCase : option.getOps<OptionCaseOp>())
1242 cache[{option.getSymNameAttr(), optionCase.getSymNameAttr()}] =
1243 optionCase.getCaseMacroAttr();
1248 StringAttr caseName)
const {
1249 auto it = cache.find({optionName, caseName});
1250 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)
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.
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.
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.
void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs)
Emit a connect between two values.
void makeCommonPrefix(SmallString< 64 > &a, StringRef b)
Truncate a to the common prefix of a and b.
IntegerAttr getIntZerosAttr(Type type)
Utility for generating a constant zero attribute.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.