18 #include "mlir/IR/ImplicitLocOpBuilder.h"
19 #include "llvm/ADT/TypeSwitch.h"
20 #include "llvm/Support/Path.h"
22 using namespace circt;
23 using namespace firrtl;
27 ImplicitLocOpBuilder locBuilder(loc, builder.getInsertionBlock(),
28 builder.getInsertionPoint());
30 builder.restoreInsertionPoint(locBuilder.saveInsertionPoint());
36 auto dstFType = type_cast<FIRRTLType>(dst.getType());
37 auto srcFType = type_cast<FIRRTLType>(src.getType());
38 auto dstType = type_dyn_cast<FIRRTLBaseType>(dstFType);
39 auto srcType = type_dyn_cast<FIRRTLBaseType>(srcFType);
43 if (type_isa<RefType>(dstFType)) {
44 if (dstFType != srcFType)
45 src = builder.create<RefCastOp>(dstFType, src);
46 builder.create<RefDefineOp>(dst, src);
47 }
else if (type_isa<PropertyType>(dstFType) &&
48 type_isa<PropertyType>(srcFType)) {
50 builder.create<PropAssignOp>(dst, src);
53 builder.create<ConnectOp>(dst, src);
59 if (isa<AnalogType>(dstType)) {
60 builder.create<AttachOp>(ArrayRef{dst, src});
65 if (dstType == srcType && dstType.isPassive() &&
66 !dstType.hasUninferredWidth()) {
67 builder.create<MatchingConnectOp>(dst, src);
71 if (
auto dstBundle = type_dyn_cast<BundleType>(dstType)) {
76 auto srcBundle = type_dyn_cast<BundleType>(srcType);
77 if (!srcBundle ||
numElements != srcBundle.getNumElements()) {
78 builder.create<ConnectOp>(dst, src);
82 auto dstField = builder.create<SubfieldOp>(dst, i);
83 auto srcField = builder.create<SubfieldOp>(src, i);
84 if (dstBundle.getElement(i).isFlip)
85 std::swap(dstField, srcField);
91 if (
auto dstVector = type_dyn_cast<FVectorType>(dstType)) {
96 auto srcVector = type_dyn_cast<FVectorType>(srcType);
97 if (!srcVector ||
numElements != srcVector.getNumElements()) {
98 builder.create<ConnectOp>(dst, src);
102 auto dstField = builder.create<SubindexOp>(dst, i);
103 auto srcField = builder.create<SubindexOp>(src, i);
109 if ((dstType.hasUninferredReset() || srcType.hasUninferredReset()) &&
110 dstType != srcType) {
111 srcType = dstType.getConstType(srcType.isConst());
112 src = builder.create<UninferredResetCastOp>(srcType, src);
116 auto dstWidth = dstType.getBitWidthOrSentinel();
117 auto srcWidth = srcType.getBitWidthOrSentinel();
118 if (dstWidth < 0 || srcWidth < 0) {
125 if (dstType != srcType && dstType.getWidthlessType() != srcType &&
127 src = builder.create<ConstCastOp>(dstType.getWidthlessType(), src);
130 builder.create<ConnectOp>(dst, src);
135 if (dstWidth < srcWidth) {
138 type_cast<IntType>(dstType).
getConstType(srcType.isConst());
139 bool isSignedDest = tmpType.
isSigned();
142 UIntType::get(dstType.getContext(), dstWidth, srcType.isConst());
143 src = builder.create<TailPrimOp>(tmpType, src, srcWidth - dstWidth);
146 src = builder.create<AsSIntPrimOp>(
147 dstType.getConstType(tmpType.
isConst()), src);
148 }
else if (srcWidth < dstWidth) {
150 src = builder.create<PadPrimOp>(src, dstWidth);
153 if (
auto srcType = type_cast<FIRRTLBaseType>(src.getType());
154 srcType && dstType != srcType &&
156 src = builder.create<ConstCastOp>(dstType, src);
161 if (dstType == src.getType() && dstType.isPassive() &&
162 !dstType.hasUninferredWidth()) {
163 builder.create<MatchingConnectOp>(dst, src);
165 builder.create<ConnectOp>(dst, src);
169 auto intType = type_cast<IntType>(type);
170 assert((!intType.hasWidth() ||
171 (
unsigned)intType.getWidthOrSentinel() == value.getBitWidth()) &&
172 "value / type width mismatch");
174 intType.isSigned() ? IntegerType::Signed : IntegerType::Unsigned;
183 int32_t
width = abs(type_cast<IntType>(type).getWidthOrSentinel());
190 int32_t
width = abs(type_cast<IntType>(type).getWidthOrSentinel());
192 type, APInt(
width, -1,
false,
true));
198 for (
auto *user : value.getUsers())
199 if (
auto propassign = dyn_cast<PropAssignOp>(user))
200 if (propassign.getDest() == value)
215 for (
auto *user : val.getUsers()) {
216 if (
auto connect = dyn_cast<FConnectLike>(user)) {
226 bool lookThroughNodes,
227 bool lookThroughCasts) {
232 auto updateVal = [&](Value thisVal) {
233 for (
auto *user : thisVal.getUsers()) {
234 if (
auto connect = dyn_cast<FConnectLike>(user)) {
247 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
248 FModuleOp op = cast<FModuleOp>(val.getParentBlock()->getParentOp());
249 auto direction = op.getPortDirection(blockArg.getArgNumber());
257 auto *op = val.getDefiningOp();
260 if (
auto inst = dyn_cast<InstanceOp>(op)) {
261 auto resultNo = cast<OpResult>(val).getResultNumber();
264 return inst.getResult(resultNo);
271 updateVal(op->getResult(0));
276 if (lookThroughNodes && isa<NodeOp>(op)) {
277 val = cast<NodeOp>(op).getInput();
281 if (lookThroughCasts &&
282 isa<AsUIntPrimOp, AsSIntPrimOp, AsClockPrimOp, AsAsyncResetPrimOp>(
284 val = op->getOperand(0);
289 if (isa<PadPrimOp, TailPrimOp>(op)) {
290 val = op->getOperand(0);
305 bool lookThroughNodes,
bool lookThroughCasts,
309 assert(value.getType().isPassive() &&
"this code was not tested with flips");
320 struct StackElement {
322 : dst(dst), src(src), current(current), it(current.user_begin()),
335 Value::user_iterator it;
339 SmallVector<StackElement> workStack;
346 workStack.emplace_back(dst, src, value, src.
getFieldID());
352 auto fieldRef = original;
360 auto val = fieldRef.getValue();
363 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
364 auto *parent = val.getParentBlock()->getParentOp();
365 auto module = cast<FModuleLike>(parent);
366 auto direction = module.getPortDirection(blockArg.getArgNumber());
369 if (!callback(original, fieldRef))
373 addToWorklist(original, fieldRef);
377 auto *op = val.getDefiningOp();
380 if (
auto inst = dyn_cast<InstanceOp>(op)) {
381 auto resultNo = cast<OpResult>(val).getResultNumber();
384 if (!callback(original, fieldRef))
388 addToWorklist(original, fieldRef);
394 addToWorklist(original, fieldRef);
399 if (lookThroughNodes && isa<NodeOp>(op)) {
400 auto input = cast<NodeOp>(op).getInput();
402 fieldRef = next.getSubField(fieldRef.getFieldID());
407 if (lookThroughCasts &&
408 isa<AsUIntPrimOp, AsSIntPrimOp, AsClockPrimOp, AsAsyncResetPrimOp>(
410 auto input = op->getOperand(0);
412 fieldRef = next.getSubField(fieldRef.getFieldID());
417 if (isa<PadPrimOp, TailPrimOp>(op)) {
418 auto input = op->getOperand(0);
420 fieldRef = next.getSubField(fieldRef.getFieldID());
429 if (!callback(original, fieldRef))
437 if (workStack.empty())
439 auto &back = workStack.back();
440 auto current = back.current;
442 if (back.it == current.user_end()) {
443 workStack.pop_back();
449 auto *user = *back.it++;
450 auto fieldID = back.fieldID;
452 if (
auto subfield = dyn_cast<SubfieldOp>(user)) {
453 BundleType bundleType = subfield.getInput().getType();
454 auto index = subfield.getFieldIndex();
455 auto subID = bundleType.getFieldID(index);
457 if (fieldID && index != bundleType.getIndexForFieldID(fieldID))
459 auto subRef = fieldRef.getSubField(subID);
460 auto subOriginal = original.getSubField(subID);
461 auto value = subfield.getResult();
464 workStack.emplace_back(subOriginal, subRef, value, 0);
467 workStack.emplace_back(subOriginal, subRef, value, fieldID - subID);
469 }
else if (
auto subindex = dyn_cast<SubindexOp>(user)) {
470 FVectorType vectorType = subindex.getInput().getType();
471 auto index = subindex.getIndex();
472 auto subID = vectorType.getFieldID(index);
474 if (fieldID && index != vectorType.getIndexForFieldID(fieldID))
476 auto subRef = fieldRef.getSubField(subID);
477 auto subOriginal = original.getSubField(subID);
478 auto value = subindex.getResult();
481 workStack.emplace_back(subOriginal, subRef, value, 0);
484 workStack.emplace_back(subOriginal, subRef, value, fieldID - subID);
486 }
else if (
auto connect = dyn_cast<FConnectLike>(user)) {
488 if (
connect.getDest() != current)
506 if (LLVM_UNLIKELY(!value))
510 auto *op = value.getDefiningOp();
517 return TypeSwitch<Operation *, FieldRef>(op)
518 .Case<RefCastOp, ConstCastOp, UninferredResetCastOp>(
519 [lookThroughCasts](
auto op) {
520 if (!lookThroughCasts)
524 .Case<SubfieldOp, OpenSubfieldOp, SubindexOp, OpenSubindexOp, RefSubOp,
526 [](
auto subOp) {
return subOp.getAccessedField(); })
531 bool lookThroughCasts) {
532 if (LLVM_UNLIKELY(!value))
538 auto deltaRef =
getDeltaRef(value, lookThroughCasts);
542 id = deltaRef.getSubField(
id).getFieldID();
544 value = deltaRef.getValue();
549 static void getDeclName(Value value, SmallString<64> &
string,
bool nameSafe) {
552 if (
auto arg = dyn_cast<BlockArgument>(value)) {
554 auto *op = arg.getOwner()->getParentOp();
555 TypeSwitch<Operation *>(op).Case<FModuleOp, ClassOp>([&](
auto op) {
556 auto name = cast<StringAttr>(op.getPortNames()[arg.getArgNumber()]);
557 string += name.getValue();
562 auto *op = value.getDefiningOp();
563 TypeSwitch<Operation *>(op)
564 .Case<ObjectOp>([&](ObjectOp op) {
565 string += op.getInstanceName();
568 .Case<InstanceOp, MemOp>([&](
auto op) {
569 string += op.getName();
570 string += nameSafe ?
"_" :
".";
571 string += op.getPortName(cast<OpResult>(value).getResultNumber())
575 .Case<FNamableOp>([&](
auto op) {
576 string += op.getName();
579 .Case<mlir::UnrealizedConversionCastOp>(
580 [&](mlir::UnrealizedConversionCastOp cast) {
582 if (cast.getNumResults() == 1 && cast.getNumOperands() == 1 &&
583 cast.getResult(0).getType() == cast.getOperand(0).getType()) {
584 value = cast.getInputs()[0];
599 std::pair<std::string, bool>
601 SmallString<64> name;
604 bool rootKnown = !name.empty();
606 auto type = value.getType();
610 if (
auto refTy = type_dyn_cast<RefType>(type))
611 type = refTy.getType();
613 if (
auto bundleType = type_dyn_cast<BundleType>(type)) {
614 auto index = bundleType.getIndexForFieldID(localID);
616 auto &element = bundleType.getElements()[index];
618 name += nameSafe ?
"_" :
".";
619 name += element.name.getValue();
622 localID = localID - bundleType.getFieldID(index);
623 }
else if (
auto bundleType = type_dyn_cast<OpenBundleType>(type)) {
624 auto index = bundleType.getIndexForFieldID(localID);
626 auto &element = bundleType.getElements()[index];
628 name += nameSafe ?
"_" :
".";
629 name += element.name.getValue();
632 localID = localID - bundleType.getFieldID(index);
633 }
else if (
auto vecType = type_dyn_cast<FVectorType>(type)) {
634 auto index = vecType.getIndexForFieldID(localID);
635 name += nameSafe ?
"_" :
"[";
636 name += std::to_string(index);
640 type = vecType.getElementType();
641 localID = localID - vecType.getFieldID(index);
642 }
else if (
auto vecType = type_dyn_cast<OpenVectorType>(type)) {
643 auto index = vecType.getIndexForFieldID(localID);
644 name += nameSafe ?
"_" :
"[";
645 name += std::to_string(index);
649 type = vecType.getElementType();
650 localID = localID - vecType.getFieldID(index);
651 }
else if (
auto enumType = type_dyn_cast<FEnumType>(type)) {
652 auto index = enumType.getIndexForFieldID(localID);
653 auto &element = enumType.getElements()[index];
654 name += nameSafe ?
"_" :
".";
655 name += element.name.getValue();
657 localID = localID - enumType.getFieldID(index);
658 }
else if (
auto classType = type_dyn_cast<ClassType>(type)) {
659 auto index = classType.getIndexForFieldID(localID);
660 auto &element = classType.getElement(index);
661 name += nameSafe ?
"_" :
".";
662 name += element.name.getValue();
664 localID = localID - classType.getFieldID(index);
670 llvm_unreachable(
"unsupported type");
674 return {name.str().str(), rootKnown};
682 Value value,
unsigned fieldID) {
684 while (fieldID != 0) {
686 .
Case<BundleType, OpenBundleType>([&](
auto bundle) {
687 auto index = bundle.getIndexForFieldID(fieldID);
688 value = builder.create<SubfieldOp>(value, index);
689 fieldID -= bundle.getFieldID(index);
691 .Case<FVectorType, OpenVectorType>([&](
auto vector) {
692 auto index = vector.getIndexForFieldID(fieldID);
693 value = builder.create<SubindexOp>(value, index);
694 fieldID -= vector.getFieldID(index);
696 .Case<RefType>([&](
auto reftype) {
698 .template Case<BundleType, FVectorType>([&](
auto type) {
699 auto index = type.getIndexForFieldID(fieldID);
700 value = builder.create<RefSubOp>(value, index);
701 fieldID -= type.getFieldID(index);
703 .Default([&](
auto _) {
704 llvm::report_fatal_error(
705 "unrecognized type for indexing through with fieldID");
709 .Default([&](
auto _) {
710 llvm::report_fatal_error(
711 "unrecognized type for indexing through with fieldID");
731 return fn(0, type,
false);
733 uint64_t fieldID = 0;
734 auto recurse = [&](
auto &&f,
FIRRTLBaseType type,
bool isFlip) ->
void {
736 .
Case<BundleType>([&](BundleType bundle) {
737 for (
size_t i = 0, e = bundle.getNumElements(); i < e; ++i) {
739 f(f, bundle.getElementType(i),
740 isFlip ^ bundle.getElement(i).isFlip);
743 .
template Case<FVectorType>([&](FVectorType vector) {
744 for (
size_t i = 0, e = vector.getNumElements(); i < e; ++i) {
746 f(f, vector.getElementType(), isFlip);
749 .
template Case<FEnumType>([&](FEnumType fenum) {
750 for (
size_t i = 0, e = fenum.getNumElements(); i < e; ++i) {
752 f(f, fenum.getElementType(i), isFlip);
756 assert(groundType.isGround() &&
757 "only ground types are expected here");
758 fn(fieldID, groundType, isFlip);
761 recurse(recurse, type,
false);
768 if (
auto arg = dyn_cast<BlockArgument>(root)) {
769 auto mod = cast<FModuleLike>(arg.getOwner()->getParentOp());
780 return TypeSwitch<Operation *, FieldRef>(ist.
getOp())
781 .Case<FModuleOp>([&](
auto fmod) {
787 auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(ist.
getOp());
788 assert(symOp && symOp.getTargetResultIndex() &&
789 (symOp.supportsPerFieldSymbols() || ist.
getField() == 0));
795 MLIRContext *context, hw::InnerSymAttr attr, uint64_t fieldID,
797 SmallVector<hw::InnerSymPropertiesAttr> props;
800 if (
auto sym = attr.getSymIfExists(fieldID))
802 llvm::append_range(props, attr.getProps());
812 [](
auto &p,
auto &q) {
return p.getFieldID() < q.getFieldID(); });
820 if (
auto mod = dyn_cast<FModuleOp>(target.
getOp())) {
821 auto portIdx = target.
getPort();
822 assert(portIdx < mod.getNumPorts());
826 mod.setPortSymbolAttr(portIdx, attr);
831 if (
auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(target.
getOp())) {
835 symOp.setInnerSymbolAttr(attr);
840 assert(0 &&
"target must be port of FModuleOp or InnerSymbol");
848 module = cast<FModuleLike>(target.
getOp());
850 module = target.
getOp()->getParentOfType<FModuleOp>();
854 return getNamespace(module);
863 auto mod = target.
isPort() ? dyn_cast<FModuleOp>(target.
getOp())
864 : target.
getOp()->getParentOfType<FModuleOp>();
866 "must be an operation inside an FModuleOp or port of FModuleOp");
872 std::pair<bool, std::optional<mlir::LocationAttr>>
874 StringAttr &locatorFilenameCache,
875 FileLineColLoc &fileLineColLocCache,
876 MLIRContext *context) {
878 if (!spelling.starts_with(
"@[") || !spelling.ends_with(
"]"))
879 return {
false, std::nullopt};
881 spelling = spelling.drop_front(2).drop_back(1);
885 auto decodeLocator = [&](StringRef input,
unsigned &resultLineNo,
886 unsigned &resultColNo) -> StringRef {
888 auto spaceLoc = input.find_last_of(
' ');
889 if (spaceLoc == StringRef::npos)
892 auto filename = input.take_front(spaceLoc);
893 auto lineAndColumn = input.drop_front(spaceLoc + 1);
897 StringRef lineStr, colStr;
898 std::tie(lineStr, colStr) = lineAndColumn.split(
':');
901 if (lineStr.getAsInteger(10, resultLineNo))
903 if (!colStr.empty()) {
904 if (colStr.front() !=
'{') {
905 if (colStr.getAsInteger(10, resultColNo))
909 if (colStr.drop_front().split(
',').first.getAsInteger(10, resultColNo))
917 unsigned lineNo = 0, columnNo = 0;
918 StringRef filename = decodeLocator(spelling, lineNo, columnNo);
919 if (filename.empty())
920 return {
false, std::nullopt};
925 return {
true, std::nullopt};
929 auto getFileLineColLoc = [&](StringRef filename,
unsigned lineNo,
930 unsigned columnNo) -> FileLineColLoc {
932 StringAttr filenameId = locatorFilenameCache;
933 if (filenameId.str() != filename) {
935 locatorFilenameCache = filenameId =
StringAttr::get(context, filename);
939 return fileLineColLocCache =
944 auto result = fileLineColLocCache;
945 if (result && result.getLine() == lineNo && result.getColumn() == columnNo)
948 return fileLineColLocCache =
960 SmallVector<Location> extraLocs;
961 auto spaceLoc = filename.find_last_of(
' ');
962 while (spaceLoc != StringRef::npos) {
965 unsigned nextLineNo = 0, nextColumnNo = 0;
967 decodeLocator(filename.take_front(spaceLoc), nextLineNo, nextColumnNo);
970 if (nextFilename.empty())
976 getFileLineColLoc(filename.drop_front(spaceLoc + 1), lineNo, columnNo);
977 extraLocs.push_back(loc);
978 filename = nextFilename;
980 columnNo = nextColumnNo;
981 spaceLoc = filename.find_last_of(
' ');
984 mlir::LocationAttr result = getFileLineColLoc(filename, lineNo, columnNo);
985 if (!extraLocs.empty()) {
986 extraLocs.push_back(result);
987 std::reverse(extraLocs.begin(), extraLocs.end());
990 return {
true, result};
997 Type type, std::optional<Location> loc,
998 llvm::function_ref<hw::TypeAliasType(Type, BaseTypeAliasType, Location)>
1000 auto firType = type_dyn_cast<FIRRTLBaseType>(type);
1006 if (BaseTypeAliasType aliasType = dyn_cast<BaseTypeAliasType>(firType)) {
1009 type =
lowerType(aliasType.getInnerType(), loc, getTypeDeclFn);
1010 return getTypeDeclFn(type, aliasType, *loc);
1013 firType = firType.getPassiveType();
1015 if (
auto bundle = type_dyn_cast<BundleType>(firType)) {
1016 mlir::SmallVector<hw::StructType::FieldInfo, 8> hwfields;
1017 for (
auto element : bundle) {
1018 Type etype =
lowerType(element.type, loc, getTypeDeclFn);
1021 hwfields.push_back(hw::StructType::FieldInfo{element.name, etype});
1025 if (
auto vec = type_dyn_cast<FVectorType>(firType)) {
1026 auto elemTy =
lowerType(vec.getElementType(), loc, getTypeDeclFn);
1031 if (
auto fenum = type_dyn_cast<FEnumType>(firType)) {
1032 mlir::SmallVector<hw::UnionType::FieldInfo, 8> hwfields;
1033 SmallVector<Attribute> names;
1035 for (
auto element : fenum) {
1036 Type etype =
lowerType(element.type, loc, getTypeDeclFn);
1039 hwfields.push_back(hw::UnionType::FieldInfo{element.name, etype, 0});
1040 names.push_back(element.name);
1041 if (!isa<UIntType>(element.type) ||
1042 element.type.getBitWidthOrSentinel() != 0)
1050 hw::StructType::FieldInfo fields[2] = {
1055 if (type_isa<ClockType>(firType))
1058 auto width = firType.getBitWidthOrSentinel();
1068 size_t e = std::min(a.size(), b.size());
1075 auto sep = llvm::sys::path::get_separator();
1076 while (!a.empty() && !a.ends_with(sep))
1081 mlir::ImplicitLocOpBuilder &builderOM) {
1083 auto *context = op->getContext();
1085 TargetKind kind = TargetKind::Reference;
1088 NamedAttrList fields;
1089 fields.append(
"id",
id);
1096 if (isa<InstanceOp, FModuleLike>(op))
1097 kind = TargetKind::Instance;
1101 return builderOM.create<PathOp>(kind, id);
assert(baseType &&"element must be base type")
MlirType uint64_t numElements
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()
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)
Return a 'const' or non-'const' version of this type.
The target of an inner symbol, the entity the symbol is a handle for.
Operation * getOp() const
Return the target's base operation. For ports, this is the module.
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.
def connect(destination, source)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
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.
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.