18#include "mlir/IR/ImplicitLocOpBuilder.h"
19#include "llvm/ADT/SmallString.h"
20#include "llvm/ADT/TypeSwitch.h"
21#include "llvm/Support/Path.h"
24using namespace firrtl;
28 ImplicitLocOpBuilder locBuilder(loc, builder.getInsertionBlock(),
29 builder.getInsertionPoint());
31 builder.restoreInsertionPoint(locBuilder.saveInsertionPoint());
37 auto dstFType = type_cast<FIRRTLType>(dst.getType());
38 auto srcFType = type_cast<FIRRTLType>(src.getType());
39 auto dstType = type_dyn_cast<FIRRTLBaseType>(dstFType);
40 auto srcType = type_dyn_cast<FIRRTLBaseType>(srcFType);
44 if (type_isa<RefType>(dstFType)) {
45 if (dstFType != srcFType)
46 src = RefCastOp::create(builder, dstFType, src);
47 RefDefineOp::create(builder, dst, src);
48 }
else if (type_isa<PropertyType>(dstFType) &&
49 type_isa<PropertyType>(srcFType)) {
51 PropAssignOp::create(builder, dst, src);
52 }
else if (type_isa<DomainType>(dstFType) &&
53 type_isa<DomainType>(srcFType)) {
54 DomainDefineOp::create(builder, dst, src);
57 ConnectOp::create(builder, dst, src);
63 if (isa<AnalogType>(dstType)) {
64 AttachOp::create(builder, ArrayRef{dst, src});
69 if (dstType == srcType && dstType.isPassive() &&
70 !dstType.hasUninferredWidth()) {
71 MatchingConnectOp::create(builder, dst, src);
75 if (
auto dstBundle = type_dyn_cast<BundleType>(dstType)) {
80 auto srcBundle = type_dyn_cast<BundleType>(srcType);
81 if (!srcBundle ||
numElements != srcBundle.getNumElements()) {
82 ConnectOp::create(builder, dst, src);
86 auto dstField = SubfieldOp::create(builder, dst, i);
87 auto srcField = SubfieldOp::create(builder, src, i);
88 if (dstBundle.getElement(i).isFlip)
89 std::swap(dstField, srcField);
95 if (
auto dstVector = type_dyn_cast<FVectorType>(dstType)) {
100 auto srcVector = type_dyn_cast<FVectorType>(srcType);
101 if (!srcVector ||
numElements != srcVector.getNumElements()) {
102 ConnectOp::create(builder, dst, src);
106 auto dstField = SubindexOp::create(builder, dst, i);
107 auto srcField = SubindexOp::create(builder, src, i);
113 if ((dstType.hasUninferredReset() || srcType.hasUninferredReset()) &&
114 dstType != srcType) {
115 srcType = dstType.getConstType(srcType.isConst());
116 src = UninferredResetCastOp::create(builder, srcType, src);
120 auto dstWidth = dstType.getBitWidthOrSentinel();
121 auto srcWidth = srcType.getBitWidthOrSentinel();
122 if (dstWidth < 0 || srcWidth < 0) {
129 if (dstType != srcType && dstType.getWidthlessType() != srcType &&
131 src = ConstCastOp::create(builder, dstType.getWidthlessType(), src);
134 ConnectOp::create(builder, dst, src);
139 if (dstWidth < srcWidth) {
142 type_cast<IntType>(dstType).
getConstType(srcType.isConst());
143 bool isSignedDest = tmpType.
isSigned();
146 UIntType::get(dstType.getContext(), dstWidth, srcType.isConst());
147 src = TailPrimOp::create(builder, tmpType, src, srcWidth - dstWidth);
150 src = AsSIntPrimOp::create(builder,
151 dstType.getConstType(tmpType.
isConst()), src);
152 }
else if (srcWidth < dstWidth) {
154 src = PadPrimOp::create(builder, src, dstWidth);
157 if (
auto srcType = type_cast<FIRRTLBaseType>(src.getType());
158 srcType && dstType != srcType &&
160 src = ConstCastOp::create(builder, dstType, src);
165 if (dstType == src.getType() && dstType.isPassive() &&
166 !dstType.hasUninferredWidth()) {
167 MatchingConnectOp::create(builder, dst, src);
169 ConnectOp::create(builder, dst, src);
173 auto intType = type_cast<IntType>(type);
174 assert((!intType.hasWidth() ||
175 (
unsigned)intType.getWidthOrSentinel() == value.getBitWidth()) &&
176 "value / type width mismatch");
178 intType.isSigned() ? IntegerType::Signed : IntegerType::Unsigned;
180 IntegerType::get(type.getContext(), value.getBitWidth(), intSign);
181 return IntegerAttr::get(attrType, value);
187 int32_t width = abs(type_cast<IntType>(type).getWidthOrSentinel());
194 int32_t width = abs(type_cast<IntType>(type).getWidthOrSentinel());
196 type, APInt(width, -1,
false,
true));
202 for (
auto *user : value.getUsers())
203 if (
auto propassign = dyn_cast<PropAssignOp>(user))
204 if (propassign.getDest() == value)
219 for (
auto *user : val.getUsers()) {
220 if (
auto connect = dyn_cast<FConnectLike>(user)) {
221 if (connect.getDest() != val)
223 return connect.getSrc();
230 bool lookThroughNodes,
231 bool lookThroughCasts) {
236 auto updateVal = [&](Value thisVal) {
237 for (
auto *user : thisVal.getUsers()) {
238 if (
auto connect = dyn_cast<FConnectLike>(user)) {
239 if (connect.getDest() != val)
241 val = connect.getSrc();
251 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
252 FModuleOp op = cast<FModuleOp>(val.getParentBlock()->getParentOp());
253 auto direction = op.getPortDirection(blockArg.getArgNumber());
255 if (direction == Direction::In)
261 auto *op = val.getDefiningOp();
264 if (
auto inst = dyn_cast<InstanceOp>(op)) {
265 auto resultNo = cast<OpResult>(val).getResultNumber();
267 if (inst.getPortDirection(resultNo) == Direction::Out)
268 return inst.getResult(resultNo);
275 updateVal(op->getResult(0));
280 if (lookThroughNodes && isa<NodeOp>(op)) {
281 val = cast<NodeOp>(op).getInput();
285 if (lookThroughCasts &&
286 isa<AsUIntPrimOp, AsSIntPrimOp, AsClockPrimOp, AsAsyncResetPrimOp>(
288 val = op->getOperand(0);
293 if (isa<PadPrimOp, TailPrimOp>(op)) {
294 val = op->getOperand(0);
309 bool lookThroughNodes,
bool lookThroughCasts,
313 assert(value.getType().isPassive() &&
"this code was not tested with flips");
324 struct StackElement {
326 : dst(dst), src(src), current(current), it(current.user_begin()),
339 Value::user_iterator it;
343 SmallVector<StackElement> workStack;
349 auto value = src.getValue();
350 workStack.emplace_back(dst, src, value, src.
getFieldID());
356 auto fieldRef = original;
364 auto val = fieldRef.getValue();
367 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
368 auto *parent = val.getParentBlock()->getParentOp();
369 auto module = cast<FModuleLike>(parent);
370 auto direction =
module.getPortDirection(blockArg.getArgNumber());
372 if (direction == Direction::In) {
373 if (!callback(original, fieldRef))
377 addToWorklist(original, fieldRef);
381 auto *op = val.getDefiningOp();
384 if (
auto inst = dyn_cast<InstanceOp>(op)) {
385 auto resultNo = cast<OpResult>(val).getResultNumber();
387 if (inst.getPortDirection(resultNo) == Direction::Out) {
388 if (!callback(original, fieldRef))
392 addToWorklist(original, fieldRef);
398 addToWorklist(original, fieldRef);
403 if (lookThroughNodes && isa<NodeOp>(op)) {
404 auto input = cast<NodeOp>(op).getInput();
406 fieldRef = next.getSubField(fieldRef.getFieldID());
411 if (lookThroughCasts &&
412 isa<AsUIntPrimOp, AsSIntPrimOp, AsClockPrimOp, AsAsyncResetPrimOp>(
414 auto input = op->getOperand(0);
416 fieldRef = next.getSubField(fieldRef.getFieldID());
421 if (isa<PadPrimOp, TailPrimOp>(op)) {
422 auto input = op->getOperand(0);
424 fieldRef = next.getSubField(fieldRef.getFieldID());
433 if (!callback(original, fieldRef))
441 if (workStack.empty())
443 auto &back = workStack.back();
444 auto current = back.current;
446 if (back.it == current.user_end()) {
447 workStack.pop_back();
453 auto *user = *back.it++;
454 auto fieldID = back.fieldID;
456 if (
auto subfield = dyn_cast<SubfieldOp>(user)) {
457 BundleType bundleType = subfield.getInput().getType();
458 auto index = subfield.getFieldIndex();
459 auto subID = bundleType.getFieldID(index);
461 if (fieldID && index != bundleType.getIndexForFieldID(fieldID))
463 auto subRef = fieldRef.getSubField(subID);
464 auto subOriginal = original.getSubField(subID);
465 auto value = subfield.getResult();
468 workStack.emplace_back(subOriginal, subRef, value, 0);
471 workStack.emplace_back(subOriginal, subRef, value, fieldID - subID);
473 }
else if (
auto subindex = dyn_cast<SubindexOp>(user)) {
474 FVectorType vectorType = subindex.getInput().getType();
475 auto index = subindex.getIndex();
476 auto subID = vectorType.getFieldID(index);
478 if (fieldID && index != vectorType.getIndexForFieldID(fieldID))
480 auto subRef = fieldRef.getSubField(subID);
481 auto subOriginal = original.getSubField(subID);
482 auto value = subindex.getResult();
485 workStack.emplace_back(subOriginal, subRef, value, 0);
488 workStack.emplace_back(subOriginal, subRef, value, fieldID - subID);
490 }
else if (
auto connect = dyn_cast<FConnectLike>(user)) {
492 if (connect.getDest() != current)
510 if (LLVM_UNLIKELY(!value))
514 auto *op = value.getDefiningOp();
521 return TypeSwitch<Operation *, FieldRef>(op)
522 .Case<RefCastOp, ConstCastOp, UninferredResetCastOp>(
523 [lookThroughCasts](
auto op) {
524 if (!lookThroughCasts)
528 .Case<SubfieldOp, OpenSubfieldOp, SubindexOp, OpenSubindexOp, RefSubOp,
530 [](
auto subOp) {
return subOp.getAccessedField(); })
535 bool lookThroughCasts) {
536 if (LLVM_UNLIKELY(!value))
542 auto deltaRef =
getDeltaRef(value, lookThroughCasts);
546 id = deltaRef.getSubField(
id).getFieldID();
548 value = deltaRef.getValue();
553static void getDeclName(Value value, SmallString<64> &
string,
bool nameSafe) {
556 if (
auto arg = dyn_cast<BlockArgument>(value)) {
558 auto *op = arg.getOwner()->getParentOp();
559 TypeSwitch<Operation *>(op).Case<FModuleOp, ClassOp>([&](
auto op) {
560 auto name = cast<StringAttr>(op.getPortNames()[arg.getArgNumber()]);
561 string += name.getValue();
566 auto *op = value.getDefiningOp();
567 TypeSwitch<Operation *>(op)
568 .Case<ObjectOp>([&](ObjectOp op) {
569 string += op.getInstanceName();
572 .Case<InstanceOp, MemOp>([&](
auto op) {
573 string += op.getName();
574 string += nameSafe ?
"_" :
".";
575 string += op.getPortName(cast<OpResult>(value).getResultNumber());
578 .Case<FNamableOp>([&](
auto op) {
579 string += op.getName();
582 .Case<mlir::UnrealizedConversionCastOp>(
583 [&](mlir::UnrealizedConversionCastOp cast) {
585 if (cast.getNumResults() == 1 && cast.getNumOperands() == 1 &&
586 cast.getResult(0).getType() == cast.getOperand(0).getType()) {
587 value = cast.getInputs()[0];
602std::pair<std::string, bool>
604 SmallString<64> name;
607 bool rootKnown = !name.empty();
609 auto type = value.getType();
613 if (
auto refTy = type_dyn_cast<RefType>(type))
614 type = refTy.getType();
616 if (
auto bundleType = type_dyn_cast<BundleType>(type)) {
617 auto index = bundleType.getIndexForFieldID(localID);
619 auto &element = bundleType.getElements()[index];
621 name += nameSafe ?
"_" :
".";
622 name += element.name.getValue();
625 localID = localID - bundleType.getFieldID(index);
626 }
else if (
auto bundleType = type_dyn_cast<OpenBundleType>(type)) {
627 auto index = bundleType.getIndexForFieldID(localID);
629 auto &element = bundleType.getElements()[index];
631 name += nameSafe ?
"_" :
".";
632 name += element.name.getValue();
635 localID = localID - bundleType.getFieldID(index);
636 }
else if (
auto vecType = type_dyn_cast<FVectorType>(type)) {
637 auto index = vecType.getIndexForFieldID(localID);
638 name += nameSafe ?
"_" :
"[";
639 name += std::to_string(index);
643 type = vecType.getElementType();
644 localID = localID - vecType.getFieldID(index);
645 }
else if (
auto vecType = type_dyn_cast<OpenVectorType>(type)) {
646 auto index = vecType.getIndexForFieldID(localID);
647 name += nameSafe ?
"_" :
"[";
648 name += std::to_string(index);
652 type = vecType.getElementType();
653 localID = localID - vecType.getFieldID(index);
654 }
else if (
auto classType = type_dyn_cast<ClassType>(type)) {
655 auto index = classType.getIndexForFieldID(localID);
656 auto &element = classType.getElement(index);
657 name += nameSafe ?
"_" :
".";
658 name += element.name.getValue();
660 localID = localID - classType.getFieldID(index);
666 llvm_unreachable(
"unsupported type");
670 return {name.str().str(), rootKnown};
678 Value value,
unsigned fieldID) {
680 while (fieldID != 0) {
682 .
Case<BundleType, OpenBundleType>([&](
auto bundle) {
683 auto index = bundle.getIndexForFieldID(fieldID);
684 value = SubfieldOp::create(builder, value, index);
685 fieldID -= bundle.getFieldID(index);
687 .Case<FVectorType, OpenVectorType>([&](
auto vector) {
688 auto index = vector.getIndexForFieldID(fieldID);
689 value = SubindexOp::create(builder, value, index);
690 fieldID -= vector.getFieldID(index);
692 .Case<RefType>([&](
auto reftype) {
694 .template Case<BundleType, FVectorType>([&](
auto type) {
695 auto index = type.getIndexForFieldID(fieldID);
696 value = RefSubOp::create(builder, value, index);
697 fieldID -= type.getFieldID(index);
699 .Default([&](
auto _) {
700 llvm::report_fatal_error(
701 "unrecognized type for indexing through with fieldID");
705 .Default([&](
auto _) {
706 llvm::report_fatal_error(
707 "unrecognized type for indexing through with fieldID");
727 return fn(0, type,
false);
729 uint64_t fieldID = 0;
730 auto recurse = [&](
auto &&f,
FIRRTLBaseType type,
bool isFlip) ->
void {
732 .
Case<BundleType>([&](BundleType bundle) {
733 for (
size_t i = 0, e = bundle.getNumElements(); i < e; ++i) {
735 f(f, bundle.getElementType(i),
736 isFlip ^ bundle.getElement(i).isFlip);
739 .
template Case<FVectorType>([&](FVectorType vector) {
740 for (
size_t i = 0, e = vector.getNumElements(); i < e; ++i) {
742 f(f, vector.getElementType(), isFlip);
745 .
template Case<FEnumType>([&](FEnumType fenum) {
749 fn(fieldID, fenum, isFlip);
752 assert(groundType.isGround() &&
753 "only ground types are expected here");
754 fn(fieldID, groundType, isFlip);
757 recurse(recurse, type,
false);
764 if (
auto arg = dyn_cast<BlockArgument>(root)) {
765 auto mod = cast<FModuleLike>(arg.getOwner()->getParentOp());
776 return TypeSwitch<Operation *, FieldRef>(ist.
getOp())
777 .Case<FModuleOp>([&](
auto fmod) {
783 auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(ist.
getOp());
784 assert(symOp && symOp.getTargetResultIndex() &&
785 (symOp.supportsPerFieldSymbols() || ist.
getField() == 0));
791 MLIRContext *
context, hw::InnerSymAttr attr, uint64_t fieldID,
793 SmallVector<hw::InnerSymPropertiesAttr> props;
796 if (
auto sym = attr.getSymIfExists(fieldID))
798 llvm::append_range(props, attr.getProps());
802 auto sym = StringAttr::get(
context, getNamespace().newName(
"sym"));
803 props.push_back(hw::InnerSymPropertiesAttr::get(
808 [](
auto &p,
auto &q) {
return p.getFieldID() < q.getFieldID(); });
809 return {hw::InnerSymAttr::get(
context, props), sym};
816 if (
auto mod = dyn_cast<FModuleLike>(target.
getOp())) {
817 auto portIdx = target.
getPort();
818 assert(portIdx < mod.getNumPorts());
822 mod.setPortSymbolAttr(portIdx, attr);
827 if (
auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(target.
getOp())) {
831 symOp.setInnerSymbolAttr(attr);
836 assert(0 &&
"target must be port of FModuleLike or InnerSymbol");
844 module = cast<FModuleLike>(target.getOp());
846 module = target.getOp()->getParentOfType<FModuleOp>();
850 return getNamespace(module);
859 auto mod = target.
isPort() ? dyn_cast<FModuleLike>(target.
getOp())
860 : target.
getOp()->getParentOfType<FModuleOp>();
862 "must be an operation inside an FModuleOp or port of FModuleLike");
863 return hw::InnerRefAttr::get(SymbolTable::getSymbolName(mod),
868std::pair<bool, std::optional<mlir::LocationAttr>>
870 StringAttr &locatorFilenameCache,
871 FileLineColLoc &fileLineColLocCache,
874 if (!spelling.starts_with(
"@[") || !spelling.ends_with(
"]"))
875 return {
false, std::nullopt};
877 spelling = spelling.drop_front(2).drop_back(1);
881 auto decodeLocator = [&](StringRef input,
unsigned &resultLineNo,
882 unsigned &resultColNo) -> StringRef {
884 auto spaceLoc = input.find_last_of(
' ');
885 if (spaceLoc == StringRef::npos)
888 auto filename = input.take_front(spaceLoc);
889 auto lineAndColumn = input.drop_front(spaceLoc + 1);
893 StringRef lineStr, colStr;
894 std::tie(lineStr, colStr) = lineAndColumn.split(
':');
897 if (lineStr.getAsInteger(10, resultLineNo))
899 if (!colStr.empty()) {
900 if (colStr.front() !=
'{') {
901 if (colStr.getAsInteger(10, resultColNo))
905 if (colStr.drop_front().split(
',').first.getAsInteger(10, resultColNo))
913 unsigned lineNo = 0, columnNo = 0;
914 StringRef filename = decodeLocator(spelling, lineNo, columnNo);
915 if (filename.empty())
916 return {
false, std::nullopt};
921 return {
true, std::nullopt};
925 auto getFileLineColLoc = [&](StringRef filename,
unsigned lineNo,
926 unsigned columnNo) -> FileLineColLoc {
928 StringAttr filenameId = locatorFilenameCache;
929 if (filenameId.str() != filename) {
931 locatorFilenameCache = filenameId = StringAttr::get(
context, filename);
935 return fileLineColLocCache =
936 FileLineColLoc::get(filenameId, lineNo, columnNo);
940 auto result = fileLineColLocCache;
941 if (result && result.getLine() == lineNo && result.getColumn() == columnNo)
944 return fileLineColLocCache =
945 FileLineColLoc::get(filenameId, lineNo, columnNo);
956 SmallVector<Location> extraLocs;
957 auto spaceLoc = filename.find_last_of(
' ');
958 while (spaceLoc != StringRef::npos) {
961 unsigned nextLineNo = 0, nextColumnNo = 0;
963 decodeLocator(filename.take_front(spaceLoc), nextLineNo, nextColumnNo);
966 if (nextFilename.empty())
972 getFileLineColLoc(filename.drop_front(spaceLoc + 1), lineNo, columnNo);
973 extraLocs.push_back(loc);
974 filename = nextFilename;
976 columnNo = nextColumnNo;
977 spaceLoc = filename.find_last_of(
' ');
980 mlir::LocationAttr result = getFileLineColLoc(filename, lineNo, columnNo);
981 if (!extraLocs.empty()) {
982 extraLocs.push_back(result);
983 std::reverse(extraLocs.begin(), extraLocs.end());
984 result = FusedLoc::get(
context, extraLocs);
986 return {
true, result};
993 Type type, std::optional<Location> loc,
994 llvm::function_ref<hw::TypeAliasType(Type, BaseTypeAliasType, Location)>
996 auto firType = type_dyn_cast<FIRRTLBaseType>(type);
1002 if (BaseTypeAliasType aliasType = dyn_cast<BaseTypeAliasType>(firType)) {
1004 loc = UnknownLoc::get(type.getContext());
1005 type =
lowerType(aliasType.getInnerType(), loc, getTypeDeclFn);
1006 return getTypeDeclFn(type, aliasType, *loc);
1009 firType = firType.getPassiveType();
1011 if (
auto bundle = type_dyn_cast<BundleType>(firType)) {
1012 mlir::SmallVector<hw::StructType::FieldInfo, 8> hwfields;
1013 for (
auto element : bundle) {
1014 Type etype =
lowerType(element.type, loc, getTypeDeclFn);
1017 hwfields.push_back(hw::StructType::FieldInfo{element.name, etype});
1019 return hw::StructType::get(type.getContext(), hwfields);
1021 if (
auto vec = type_dyn_cast<FVectorType>(firType)) {
1022 auto elemTy =
lowerType(vec.getElementType(), loc, getTypeDeclFn);
1025 return hw::ArrayType::get(elemTy, vec.getNumElements());
1027 if (
auto fenum = type_dyn_cast<FEnumType>(firType)) {
1028 mlir::SmallVector<hw::UnionType::FieldInfo, 8> hwfields;
1030 for (
auto element : fenum) {
1031 Type etype =
lowerType(element.type, loc, getTypeDeclFn);
1034 hwfields.push_back(hw::UnionType::FieldInfo{element.name, etype, 0});
1035 if (element.type.getBitWidthOrSentinel() != 0)
1038 auto tagTy = IntegerType::get(type.getContext(), fenum.getTagWidth());
1041 auto bodyTy = hw::UnionType::get(type.getContext(), hwfields);
1042 hw::StructType::FieldInfo fields[2] = {
1043 {StringAttr::get(type.getContext(),
"tag"), tagTy},
1044 {StringAttr::get(type.getContext(),
"body"), bodyTy}};
1045 return hw::StructType::get(type.getContext(), fields);
1047 if (type_isa<ClockType>(firType))
1048 return seq::ClockType::get(firType.getContext());
1050 auto width = firType.getBitWidthOrSentinel();
1052 return IntegerType::get(type.getContext(), width);
1060 size_t e = std::min(a.size(), b.size());
1067 auto sep = llvm::sys::path::get_separator();
1068 while (!a.empty() && !a.ends_with(sep))
1073 mlir::ImplicitLocOpBuilder &builderOM) {
1075 auto *
context = op->getContext();
1076 auto id = DistinctAttr::create(UnitAttr::get(
context));
1077 TargetKind kind = TargetKind::Reference;
1080 NamedAttrList fields;
1081 fields.append(
"id",
id);
1082 fields.append(
"class", StringAttr::get(
context,
"circt.tracker"));
1084 fields.append(
"circt.nonlocal", mlir::FlatSymbolRefAttr::get(nla));
1088 if (isa<InstanceOp, FModuleLike>(op))
1089 kind = TargetKind::Instance;
1093 return PathOp::create(builderOM, kind,
id);
1102 llvm::StringRef formatString,
1103 llvm::ArrayRef<mlir::Value> specOperands,
1104 mlir::StringAttr &formatStringResult,
1105 llvm::SmallVectorImpl<mlir::Value> &operands) {
1108 llvm::SmallString<64> validatedFormatString;
1110 for (
size_t i = 0, e = formatString.size(), opIdx = 0; i != e; ++i) {
1111 auto c = formatString[i];
1116 validatedFormatString.push_back(c);
1119 llvm::SmallString<6> width;
1120 c = formatString[++i];
1123 c = formatString[++i];
1130 return mlir::emitError(loc) <<
"ASCII character format specifiers "
1131 "('%c') may not specify a width";
1137 validatedFormatString.append(width);
1138 operands.push_back(specOperands[opIdx++]);
1142 return mlir::emitError(loc)
1143 <<
"literal percents ('%%') may not specify a width";
1147 return mlir::emitError(loc)
1148 <<
"unknown printf substitution '%" << width << c <<
"'";
1150 validatedFormatString.push_back(c);
1158 if (formatString[i + 1] !=
'{') {
1159 validatedFormatString.push_back(c);
1165 while (formatString[i] !=
'}')
1167 if (formatString[i] !=
'}')
1168 return mlir::emitError(loc)
1169 <<
"expected '}' to terminate special substitution";
1171 auto specialString = formatString.slice(start, i);
1172 if (specialString ==
"SimulationTime") {
1173 operands.push_back(TimeOp::create(builder, loc));
1174 }
else if (specialString ==
"HierarchicalModuleName") {
1175 operands.push_back(HierarchicalModuleNameOp::create(builder, loc));
1177 return mlir::emitError(loc)
1178 <<
"unknown printf substitution '" << specialString
1179 <<
"' (did you misspell it?)";
1182 validatedFormatString.append(
"{{}}");
1187 validatedFormatString.push_back(c);
1191 formatStringResult = builder.getStringAttr(validatedFormatString);
1192 return mlir::success();
assert(baseType &&"element must be base type")
MlirType uint64_t numElements
static std::unique_ptr< Context > context
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.
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.
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.