18 #include "mlir/IR/ImplicitLocOpBuilder.h"
19 #include "llvm/ADT/TypeSwitch.h"
21 using namespace circt;
22 using namespace firrtl;
26 ImplicitLocOpBuilder locBuilder(loc, builder.getInsertionBlock(),
27 builder.getInsertionPoint());
29 builder.restoreInsertionPoint(locBuilder.saveInsertionPoint());
35 auto dstFType = type_cast<FIRRTLType>(dst.getType());
36 auto srcFType = type_cast<FIRRTLType>(src.getType());
37 auto dstType = type_dyn_cast<FIRRTLBaseType>(dstFType);
38 auto srcType = type_dyn_cast<FIRRTLBaseType>(srcFType);
42 if (type_isa<RefType>(dstFType)) {
43 if (dstFType != srcFType)
44 src = builder.create<RefCastOp>(dstFType, src);
45 builder.create<RefDefineOp>(dst, src);
46 }
else if (type_isa<PropertyType>(dstFType) &&
47 type_isa<PropertyType>(srcFType)) {
49 builder.create<PropAssignOp>(dst, src);
52 builder.create<ConnectOp>(dst, src);
58 if (isa<AnalogType>(dstType)) {
59 builder.create<AttachOp>(ArrayRef{dst, src});
64 if (dstType == srcType && dstType.isPassive() &&
65 !dstType.hasUninferredWidth()) {
66 builder.create<MatchingConnectOp>(dst, src);
70 if (
auto dstBundle = type_dyn_cast<BundleType>(dstType)) {
75 auto srcBundle = type_dyn_cast<BundleType>(srcType);
76 if (!srcBundle ||
numElements != srcBundle.getNumElements()) {
77 builder.create<ConnectOp>(dst, src);
81 auto dstField = builder.create<SubfieldOp>(dst, i);
82 auto srcField = builder.create<SubfieldOp>(src, i);
83 if (dstBundle.getElement(i).isFlip)
84 std::swap(dstField, srcField);
90 if (
auto dstVector = type_dyn_cast<FVectorType>(dstType)) {
95 auto srcVector = type_dyn_cast<FVectorType>(srcType);
96 if (!srcVector ||
numElements != srcVector.getNumElements()) {
97 builder.create<ConnectOp>(dst, src);
101 auto dstField = builder.create<SubindexOp>(dst, i);
102 auto srcField = builder.create<SubindexOp>(src, i);
108 if ((dstType.hasUninferredReset() || srcType.hasUninferredReset()) &&
109 dstType != srcType) {
110 srcType = dstType.getConstType(srcType.isConst());
111 src = builder.create<UninferredResetCastOp>(srcType, src);
115 auto dstWidth = dstType.getBitWidthOrSentinel();
116 auto srcWidth = srcType.getBitWidthOrSentinel();
117 if (dstWidth < 0 || srcWidth < 0) {
124 if (dstType != srcType && dstType.getWidthlessType() != srcType &&
126 src = builder.create<ConstCastOp>(dstType.getWidthlessType(), src);
129 builder.create<ConnectOp>(dst, src);
134 if (dstWidth < srcWidth) {
137 type_cast<IntType>(dstType).
getConstType(srcType.isConst());
138 bool isSignedDest = tmpType.
isSigned();
141 UIntType::get(dstType.getContext(), dstWidth, srcType.isConst());
142 src = builder.create<TailPrimOp>(tmpType, src, srcWidth - dstWidth);
145 src = builder.create<AsSIntPrimOp>(
146 dstType.getConstType(tmpType.
isConst()), src);
147 }
else if (srcWidth < dstWidth) {
149 src = builder.create<PadPrimOp>(src, dstWidth);
152 if (
auto srcType = type_cast<FIRRTLBaseType>(src.getType());
153 srcType && dstType != srcType &&
155 src = builder.create<ConstCastOp>(dstType, src);
160 if (dstType == src.getType() && dstType.isPassive() &&
161 !dstType.hasUninferredWidth()) {
162 builder.create<MatchingConnectOp>(dst, src);
164 builder.create<ConnectOp>(dst, src);
168 auto intType = type_cast<IntType>(type);
169 assert((!intType.hasWidth() ||
170 (
unsigned)intType.getWidthOrSentinel() == value.getBitWidth()) &&
171 "value / type width mismatch");
173 intType.isSigned() ? IntegerType::Signed : IntegerType::Unsigned;
182 int32_t
width = abs(type_cast<IntType>(type).getWidthOrSentinel());
189 int32_t
width = abs(type_cast<IntType>(type).getWidthOrSentinel());
196 for (
auto *user : value.getUsers())
197 if (
auto propassign = dyn_cast<PropAssignOp>(user))
198 if (propassign.getDest() == value)
213 for (
auto *user : val.getUsers()) {
214 if (
auto connect = dyn_cast<FConnectLike>(user)) {
224 bool lookThroughNodes,
225 bool lookThroughCasts) {
230 auto updateVal = [&](Value thisVal) {
231 for (
auto *user : thisVal.getUsers()) {
232 if (
auto connect = dyn_cast<FConnectLike>(user)) {
245 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
246 FModuleOp op = cast<FModuleOp>(val.getParentBlock()->getParentOp());
247 auto direction = op.getPortDirection(blockArg.getArgNumber());
255 auto *op = val.getDefiningOp();
258 if (
auto inst = dyn_cast<InstanceOp>(op)) {
259 auto resultNo = cast<OpResult>(val).getResultNumber();
262 return inst.getResult(resultNo);
269 updateVal(op->getResult(0));
274 if (lookThroughNodes && isa<NodeOp>(op)) {
275 val = cast<NodeOp>(op).getInput();
279 if (lookThroughCasts &&
280 isa<AsUIntPrimOp, AsSIntPrimOp, AsClockPrimOp, AsAsyncResetPrimOp>(
282 val = op->getOperand(0);
287 if (isa<PadPrimOp, TailPrimOp>(op)) {
288 val = op->getOperand(0);
303 bool lookThroughNodes,
bool lookThroughCasts,
307 assert(value.getType().isPassive() &&
"this code was not tested with flips");
318 struct StackElement {
320 : dst(dst), src(src), current(current), it(current.user_begin()),
333 Value::user_iterator it;
337 SmallVector<StackElement> workStack;
344 workStack.emplace_back(dst, src, value, src.
getFieldID());
350 auto fieldRef = original;
358 auto val = fieldRef.getValue();
361 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
362 auto *parent = val.getParentBlock()->getParentOp();
363 auto module = cast<FModuleLike>(parent);
364 auto direction = module.getPortDirection(blockArg.getArgNumber());
367 if (!callback(original, fieldRef))
371 addToWorklist(original, fieldRef);
375 auto *op = val.getDefiningOp();
378 if (
auto inst = dyn_cast<InstanceOp>(op)) {
379 auto resultNo = cast<OpResult>(val).getResultNumber();
382 if (!callback(original, fieldRef))
386 addToWorklist(original, fieldRef);
392 addToWorklist(original, fieldRef);
397 if (lookThroughNodes && isa<NodeOp>(op)) {
398 auto input = cast<NodeOp>(op).getInput();
400 fieldRef = next.getSubField(fieldRef.getFieldID());
405 if (lookThroughCasts &&
406 isa<AsUIntPrimOp, AsSIntPrimOp, AsClockPrimOp, AsAsyncResetPrimOp>(
408 auto input = op->getOperand(0);
410 fieldRef = next.getSubField(fieldRef.getFieldID());
415 if (isa<PadPrimOp, TailPrimOp>(op)) {
416 auto input = op->getOperand(0);
418 fieldRef = next.getSubField(fieldRef.getFieldID());
427 if (!callback(original, fieldRef))
435 if (workStack.empty())
437 auto &back = workStack.back();
438 auto current = back.current;
440 if (back.it == current.user_end()) {
441 workStack.pop_back();
447 auto *user = *back.it++;
448 auto fieldID = back.fieldID;
450 if (
auto subfield = dyn_cast<SubfieldOp>(user)) {
451 BundleType bundleType = subfield.getInput().getType();
452 auto index = subfield.getFieldIndex();
453 auto subID = bundleType.getFieldID(index);
455 if (fieldID && index != bundleType.getIndexForFieldID(fieldID))
457 auto subRef = fieldRef.getSubField(subID);
458 auto subOriginal = original.getSubField(subID);
459 auto value = subfield.getResult();
460 workStack.emplace_back(subOriginal, subRef, value, fieldID - subID);
461 }
else if (
auto subindex = dyn_cast<SubindexOp>(user)) {
462 FVectorType vectorType = subindex.getInput().getType();
463 auto index = subindex.getIndex();
464 auto subID = vectorType.getFieldID(index);
466 if (fieldID && index != vectorType.getIndexForFieldID(fieldID))
468 auto subRef = fieldRef.getSubField(subID);
469 auto subOriginal = original.getSubField(subID);
470 auto value = subindex.getResult();
471 workStack.emplace_back(subOriginal, subRef, value, fieldID - subID);
472 }
else if (
auto connect = dyn_cast<FConnectLike>(user)) {
474 if (
connect.getDest() != current)
492 if (LLVM_UNLIKELY(!value))
496 auto *op = value.getDefiningOp();
503 return TypeSwitch<Operation *, FieldRef>(op)
504 .Case<RefCastOp, ConstCastOp, UninferredResetCastOp>(
505 [lookThroughCasts](
auto op) {
506 if (!lookThroughCasts)
510 .Case<SubfieldOp, OpenSubfieldOp, SubindexOp, OpenSubindexOp, RefSubOp,
512 [](
auto subOp) {
return subOp.getAccessedField(); })
517 bool lookThroughCasts) {
518 if (LLVM_UNLIKELY(!value))
524 auto deltaRef =
getDeltaRef(value, lookThroughCasts);
528 id = deltaRef.getSubField(
id).getFieldID();
530 value = deltaRef.getValue();
535 static void getDeclName(Value value, SmallString<64> &
string,
bool nameSafe) {
538 if (
auto arg = dyn_cast<BlockArgument>(value)) {
540 auto *op = arg.getOwner()->getParentOp();
541 TypeSwitch<Operation *>(op).Case<FModuleOp, ClassOp>([&](
auto op) {
542 auto name = cast<StringAttr>(op.getPortNames()[arg.getArgNumber()]);
543 string += name.getValue();
548 auto *op = value.getDefiningOp();
549 TypeSwitch<Operation *>(op)
550 .Case<ObjectOp>([&](ObjectOp op) {
551 string += op.getInstanceName();
554 .Case<InstanceOp, MemOp>([&](
auto op) {
555 string += op.getName();
556 string += nameSafe ?
"_" :
".";
557 string += op.getPortName(cast<OpResult>(value).getResultNumber())
561 .Case<FNamableOp>([&](
auto op) {
562 string += op.getName();
565 .Case<mlir::UnrealizedConversionCastOp>(
566 [&](mlir::UnrealizedConversionCastOp cast) {
568 if (cast.getNumResults() == 1 && cast.getNumOperands() == 1 &&
569 cast.getResult(0).getType() == cast.getOperand(0).getType()) {
570 value = cast.getInputs()[0];
585 std::pair<std::string, bool>
587 SmallString<64> name;
590 bool rootKnown = !name.empty();
592 auto type = value.getType();
596 if (
auto refTy = type_dyn_cast<RefType>(type))
597 type = refTy.getType();
599 if (
auto bundleType = type_dyn_cast<BundleType>(type)) {
600 auto index = bundleType.getIndexForFieldID(localID);
602 auto &element = bundleType.getElements()[index];
604 name += nameSafe ?
"_" :
".";
605 name += element.name.getValue();
608 localID = localID - bundleType.getFieldID(index);
609 }
else if (
auto bundleType = type_dyn_cast<OpenBundleType>(type)) {
610 auto index = bundleType.getIndexForFieldID(localID);
612 auto &element = bundleType.getElements()[index];
614 name += nameSafe ?
"_" :
".";
615 name += element.name.getValue();
618 localID = localID - bundleType.getFieldID(index);
619 }
else if (
auto vecType = type_dyn_cast<FVectorType>(type)) {
620 auto index = vecType.getIndexForFieldID(localID);
621 name += nameSafe ?
"_" :
"[";
622 name += std::to_string(index);
626 type = vecType.getElementType();
627 localID = localID - vecType.getFieldID(index);
628 }
else if (
auto vecType = type_dyn_cast<OpenVectorType>(type)) {
629 auto index = vecType.getIndexForFieldID(localID);
630 name += nameSafe ?
"_" :
"[";
631 name += std::to_string(index);
635 type = vecType.getElementType();
636 localID = localID - vecType.getFieldID(index);
637 }
else if (
auto enumType = type_dyn_cast<FEnumType>(type)) {
638 auto index = enumType.getIndexForFieldID(localID);
639 auto &element = enumType.getElements()[index];
640 name += nameSafe ?
"_" :
".";
641 name += element.name.getValue();
643 localID = localID - enumType.getFieldID(index);
644 }
else if (
auto classType = type_dyn_cast<ClassType>(type)) {
645 auto index = classType.getIndexForFieldID(localID);
646 auto &element = classType.getElement(index);
647 name += nameSafe ?
"_" :
".";
648 name += element.name.getValue();
650 localID = localID - classType.getFieldID(index);
656 llvm_unreachable(
"unsupported type");
660 return {name.str().str(), rootKnown};
668 Value value,
unsigned fieldID) {
670 while (fieldID != 0) {
672 .
Case<BundleType, OpenBundleType>([&](
auto bundle) {
673 auto index = bundle.getIndexForFieldID(fieldID);
674 value = builder.create<SubfieldOp>(value, index);
675 fieldID -= bundle.getFieldID(index);
677 .Case<FVectorType, OpenVectorType>([&](
auto vector) {
678 auto index = vector.getIndexForFieldID(fieldID);
679 value = builder.create<SubindexOp>(value, index);
680 fieldID -= vector.getFieldID(index);
682 .Case<RefType>([&](
auto reftype) {
684 .template Case<BundleType, FVectorType>([&](
auto type) {
685 auto index = type.getIndexForFieldID(fieldID);
686 value = builder.create<RefSubOp>(value, index);
687 fieldID -= type.getFieldID(index);
689 .Default([&](
auto _) {
690 llvm::report_fatal_error(
691 "unrecognized type for indexing through with fieldID");
695 .Default([&](
auto _) {
696 llvm::report_fatal_error(
697 "unrecognized type for indexing through with fieldID");
717 return fn(0, type,
false);
719 uint64_t fieldID = 0;
720 auto recurse = [&](
auto &&f,
FIRRTLBaseType type,
bool isFlip) ->
void {
722 .
Case<BundleType>([&](BundleType bundle) {
723 for (
size_t i = 0, e = bundle.getNumElements(); i < e; ++i) {
725 f(f, bundle.getElementType(i),
726 isFlip ^ bundle.getElement(i).isFlip);
729 .
template Case<FVectorType>([&](FVectorType vector) {
730 for (
size_t i = 0, e = vector.getNumElements(); i < e; ++i) {
732 f(f, vector.getElementType(), isFlip);
735 .
template Case<FEnumType>([&](FEnumType fenum) {
736 for (
size_t i = 0, e = fenum.getNumElements(); i < e; ++i) {
738 f(f, fenum.getElementType(i), isFlip);
742 assert(groundType.isGround() &&
743 "only ground types are expected here");
744 fn(fieldID, groundType, isFlip);
747 recurse(recurse, type,
false);
754 if (
auto arg = dyn_cast<BlockArgument>(root)) {
755 auto mod = cast<FModuleLike>(arg.getOwner()->getParentOp());
766 return TypeSwitch<Operation *, FieldRef>(ist.
getOp())
767 .Case<FModuleOp>([&](
auto fmod) {
773 auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(ist.
getOp());
774 assert(symOp && symOp.getTargetResultIndex() &&
775 (symOp.supportsPerFieldSymbols() || ist.
getField() == 0));
781 MLIRContext *context, hw::InnerSymAttr attr, uint64_t fieldID,
783 SmallVector<hw::InnerSymPropertiesAttr> props;
786 if (
auto sym = attr.getSymIfExists(fieldID))
788 llvm::append_range(props, attr.getProps());
798 [](
auto &p,
auto &q) {
return p.getFieldID() < q.getFieldID(); });
806 if (
auto mod = dyn_cast<FModuleOp>(target.
getOp())) {
807 auto portIdx = target.
getPort();
808 assert(portIdx < mod.getNumPorts());
812 mod.setPortSymbolsAttr(portIdx, attr);
817 if (
auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(target.
getOp())) {
821 symOp.setInnerSymbolAttr(attr);
826 assert(0 &&
"target must be port of FModuleOp or InnerSymbol");
834 module = cast<FModuleLike>(target.
getOp());
836 module = target.
getOp()->getParentOfType<FModuleOp>();
840 return getNamespace(module);
849 auto mod = target.
isPort() ? dyn_cast<FModuleOp>(target.
getOp())
850 : target.
getOp()->getParentOfType<FModuleOp>();
852 "must be an operation inside an FModuleOp or port of FModuleOp");
858 std::pair<bool, std::optional<mlir::LocationAttr>>
860 StringAttr &locatorFilenameCache,
861 FileLineColLoc &fileLineColLocCache,
862 MLIRContext *context) {
864 if (!spelling.starts_with(
"@[") || !spelling.ends_with(
"]"))
865 return {
false, std::nullopt};
867 spelling = spelling.drop_front(2).drop_back(1);
871 auto decodeLocator = [&](StringRef input,
unsigned &resultLineNo,
872 unsigned &resultColNo) -> StringRef {
874 auto spaceLoc = input.find_last_of(
' ');
875 if (spaceLoc == StringRef::npos)
878 auto filename = input.take_front(spaceLoc);
879 auto lineAndColumn = input.drop_front(spaceLoc + 1);
883 StringRef lineStr, colStr;
884 std::tie(lineStr, colStr) = lineAndColumn.split(
':');
887 if (lineStr.getAsInteger(10, resultLineNo))
889 if (!colStr.empty()) {
890 if (colStr.front() !=
'{') {
891 if (colStr.getAsInteger(10, resultColNo))
895 if (colStr.drop_front().split(
',').first.getAsInteger(10, resultColNo))
903 unsigned lineNo = 0, columnNo = 0;
904 StringRef filename = decodeLocator(spelling, lineNo, columnNo);
905 if (filename.empty())
906 return {
false, std::nullopt};
911 return {
true, std::nullopt};
915 auto getFileLineColLoc = [&](StringRef filename,
unsigned lineNo,
916 unsigned columnNo) -> FileLineColLoc {
918 StringAttr filenameId = locatorFilenameCache;
919 if (filenameId.str() != filename) {
921 locatorFilenameCache = filenameId =
StringAttr::get(context, filename);
925 return fileLineColLocCache =
930 auto result = fileLineColLocCache;
931 if (result && result.getLine() == lineNo && result.getColumn() == columnNo)
934 return fileLineColLocCache =
946 SmallVector<Location> extraLocs;
947 auto spaceLoc = filename.find_last_of(
' ');
948 while (spaceLoc != StringRef::npos) {
951 unsigned nextLineNo = 0, nextColumnNo = 0;
953 decodeLocator(filename.take_front(spaceLoc), nextLineNo, nextColumnNo);
956 if (nextFilename.empty())
962 getFileLineColLoc(filename.drop_front(spaceLoc + 1), lineNo, columnNo);
963 extraLocs.push_back(loc);
964 filename = nextFilename;
966 columnNo = nextColumnNo;
967 spaceLoc = filename.find_last_of(
' ');
970 mlir::LocationAttr result = getFileLineColLoc(filename, lineNo, columnNo);
971 if (!extraLocs.empty()) {
972 extraLocs.push_back(result);
973 std::reverse(extraLocs.begin(), extraLocs.end());
976 return {
true, result};
983 Type type, std::optional<Location> loc,
984 llvm::function_ref<hw::TypeAliasType(Type, BaseTypeAliasType, Location)>
986 auto firType = type_dyn_cast<FIRRTLBaseType>(type);
992 if (BaseTypeAliasType aliasType = dyn_cast<BaseTypeAliasType>(firType)) {
995 type =
lowerType(aliasType.getInnerType(), loc, getTypeDeclFn);
996 return getTypeDeclFn(type, aliasType, *loc);
999 firType = firType.getPassiveType();
1001 if (
auto bundle = type_dyn_cast<BundleType>(firType)) {
1002 mlir::SmallVector<hw::StructType::FieldInfo, 8> hwfields;
1003 for (
auto element : bundle) {
1004 Type etype =
lowerType(element.type, loc, getTypeDeclFn);
1007 hwfields.push_back(hw::StructType::FieldInfo{element.name, etype});
1011 if (
auto vec = type_dyn_cast<FVectorType>(firType)) {
1012 auto elemTy =
lowerType(vec.getElementType(), loc, getTypeDeclFn);
1017 if (
auto fenum = type_dyn_cast<FEnumType>(firType)) {
1018 mlir::SmallVector<hw::UnionType::FieldInfo, 8> hwfields;
1019 SmallVector<Attribute> names;
1021 for (
auto element : fenum) {
1022 Type etype =
lowerType(element.type, loc, getTypeDeclFn);
1025 hwfields.push_back(hw::UnionType::FieldInfo{element.name, etype, 0});
1026 names.push_back(element.name);
1027 if (!isa<UIntType>(element.type) ||
1028 element.type.getBitWidthOrSentinel() != 0)
1036 hw::StructType::FieldInfo fields[2] = {
1041 if (type_isa<ClockType>(firType))
1044 auto width = firType.getBitWidthOrSentinel();
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.
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.
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.
IntegerAttr getIntZerosAttr(Type type)
Utility for generating a constant zero attribute.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.