17 #include "mlir/IR/ImplicitLocOpBuilder.h"
18 #include "llvm/ADT/TypeSwitch.h"
20 using namespace circt;
21 using namespace firrtl;
25 ImplicitLocOpBuilder locBuilder(loc,
builder.getInsertionBlock(),
28 builder.restoreInsertionPoint(locBuilder.saveInsertionPoint());
34 auto dstFType = type_cast<FIRRTLType>(dst.getType());
35 auto srcFType = type_cast<FIRRTLType>(src.getType());
36 auto dstType = type_dyn_cast<FIRRTLBaseType>(dstFType);
37 auto srcType = type_dyn_cast<FIRRTLBaseType>(srcFType);
41 if (type_isa<RefType>(dstFType)) {
42 if (dstFType != srcFType)
43 src =
builder.create<RefCastOp>(dstFType, src);
44 builder.create<RefDefineOp>(dst, src);
46 builder.create<ConnectOp>(dst, src);
51 if (dstType == srcType && dstType.isPassive() &&
52 !dstType.hasUninferredWidth()) {
53 builder.create<StrictConnectOp>(dst, src);
57 if (
auto dstBundle = type_dyn_cast<BundleType>(dstType)) {
62 auto srcBundle = type_dyn_cast<BundleType>(srcType);
63 if (!srcBundle ||
numElements != srcBundle.getNumElements()) {
64 builder.create<ConnectOp>(dst, src);
68 auto dstField =
builder.create<SubfieldOp>(dst, i);
69 auto srcField =
builder.create<SubfieldOp>(src, i);
70 if (dstBundle.getElement(i).isFlip)
71 std::swap(dstField, srcField);
77 if (
auto dstVector = type_dyn_cast<FVectorType>(dstType)) {
82 auto srcVector = type_dyn_cast<FVectorType>(srcType);
83 if (!srcVector ||
numElements != srcVector.getNumElements()) {
84 builder.create<ConnectOp>(dst, src);
88 auto dstField =
builder.create<SubindexOp>(dst, i);
89 auto srcField =
builder.create<SubindexOp>(src, i);
95 if ((dstType.hasUninferredReset() || srcType.hasUninferredReset()) &&
97 srcType = dstType.getConstType(srcType.isConst());
98 src =
builder.create<UninferredResetCastOp>(srcType, src);
102 auto dstWidth = dstType.getBitWidthOrSentinel();
103 auto srcWidth = srcType.getBitWidthOrSentinel();
104 if (dstWidth < 0 || srcWidth < 0) {
111 if (dstType != srcType && dstType.getWidthlessType() != srcType &&
113 src =
builder.create<ConstCastOp>(dstType.getWidthlessType(), src);
116 builder.create<ConnectOp>(dst, src);
121 if (dstWidth < srcWidth) {
124 type_cast<IntType>(dstType).
getConstType(srcType.isConst());
125 bool isSignedDest = tmpType.
isSigned();
128 UIntType::get(dstType.getContext(), dstWidth, srcType.isConst());
129 src =
builder.create<TailPrimOp>(tmpType, src, srcWidth - dstWidth);
132 src =
builder.create<AsSIntPrimOp>(
133 dstType.getConstType(tmpType.
isConst()), src);
134 }
else if (srcWidth < dstWidth) {
136 src =
builder.create<PadPrimOp>(src, dstWidth);
139 if (
auto srcType = type_cast<FIRRTLBaseType>(src.getType());
140 srcType && dstType != srcType &&
142 src =
builder.create<ConstCastOp>(dstType, src);
147 if (dstType == src.getType() && dstType.isPassive() &&
148 !dstType.hasUninferredWidth()) {
149 builder.create<StrictConnectOp>(dst, src);
151 builder.create<ConnectOp>(dst, src);
155 auto intType = type_cast<IntType>(type);
156 assert((!intType.hasWidth() ||
157 (
unsigned)intType.getWidthOrSentinel() ==
value.getBitWidth()) &&
158 "value / type width mismatch");
160 intType.isSigned() ? IntegerType::Signed : IntegerType::Unsigned;
169 int32_t
width = abs(type_cast<IntType>(type).getWidthOrSentinel());
176 int32_t
width = abs(type_cast<IntType>(type).getWidthOrSentinel());
183 for (
auto *user :
value.getUsers())
184 if (
auto propassign = dyn_cast<PropAssignOp>(user))
185 if (propassign.getDest() ==
value)
200 for (
auto *user : val.getUsers()) {
201 if (
auto connect = dyn_cast<FConnectLike>(user)) {
211 bool lookThroughNodes,
212 bool lookThroughCasts) {
217 auto updateVal = [&](Value thisVal) {
218 for (
auto *user : thisVal.getUsers()) {
219 if (
auto connect = dyn_cast<FConnectLike>(user)) {
232 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
233 FModuleOp op = cast<FModuleOp>(val.getParentBlock()->getParentOp());
234 auto direction = op.getPortDirection(blockArg.getArgNumber());
242 auto *op = val.getDefiningOp();
245 if (
auto inst = dyn_cast<InstanceOp>(op)) {
246 auto resultNo = cast<OpResult>(val).getResultNumber();
249 return inst.getResult(resultNo);
256 updateVal(op->getResult(0));
261 if (lookThroughNodes && isa<NodeOp>(op)) {
262 val = cast<NodeOp>(op).getInput();
266 if (lookThroughCasts &&
267 isa<AsUIntPrimOp, AsSIntPrimOp, AsClockPrimOp, AsAsyncResetPrimOp>(
269 val = op->getOperand(0);
274 if (isa<PadPrimOp, TailPrimOp>(op)) {
275 val = op->getOperand(0);
290 bool lookThroughNodes,
bool lookThroughCasts,
294 assert(
value.getType().isPassive() &&
"this code was not tested with flips");
305 struct StackElement {
307 : dst(dst), src(src), current(current), it(current.user_begin()),
320 Value::user_iterator it;
324 SmallVector<StackElement> workStack;
330 auto value = src.getValue();
331 workStack.emplace_back(dst, src,
value, src.getFieldID());
337 auto fieldRef = original;
345 auto val = fieldRef.getValue();
348 if (
auto blockArg = dyn_cast<BlockArgument>(val)) {
349 auto *parent = val.getParentBlock()->getParentOp();
350 auto module = cast<FModuleLike>(parent);
351 auto direction = module.getPortDirection(blockArg.getArgNumber());
354 if (!callback(original, fieldRef))
358 addToWorklist(original, fieldRef);
362 auto *op = val.getDefiningOp();
365 if (
auto inst = dyn_cast<InstanceOp>(op)) {
366 auto resultNo = cast<OpResult>(val).getResultNumber();
369 if (!callback(original, fieldRef))
373 addToWorklist(original, fieldRef);
379 addToWorklist(original, fieldRef);
384 if (lookThroughNodes && isa<NodeOp>(op)) {
385 auto input = cast<NodeOp>(op).getInput();
387 fieldRef = next.getSubField(fieldRef.getFieldID());
392 if (lookThroughCasts &&
393 isa<AsUIntPrimOp, AsSIntPrimOp, AsClockPrimOp, AsAsyncResetPrimOp>(
395 auto input = op->getOperand(0);
397 fieldRef = next.getSubField(fieldRef.getFieldID());
402 if (isa<PadPrimOp, TailPrimOp>(op)) {
403 auto input = op->getOperand(0);
405 fieldRef = next.getSubField(fieldRef.getFieldID());
414 if (!callback(original, fieldRef))
422 if (workStack.empty())
424 auto &back = workStack.back();
425 auto current = back.current;
427 if (back.it == current.user_end()) {
428 workStack.pop_back();
434 auto *user = *back.it++;
435 auto fieldID = back.fieldID;
437 if (
auto subfield = dyn_cast<SubfieldOp>(user)) {
438 BundleType bundleType = subfield.getInput().getType();
439 auto index = subfield.getFieldIndex();
440 auto subID = bundleType.getFieldID(index);
442 if (fieldID && index != bundleType.getIndexForFieldID(fieldID))
444 auto subRef = fieldRef.getSubField(subID);
445 auto subOriginal = original.getSubField(subID);
446 auto value = subfield.getResult();
447 workStack.emplace_back(subOriginal, subRef,
value, fieldID - subID);
448 }
else if (
auto subindex = dyn_cast<SubindexOp>(user)) {
449 FVectorType vectorType = subindex.getInput().getType();
450 auto index = subindex.getIndex();
451 auto subID = vectorType.getFieldID(index);
453 if (fieldID && index != vectorType.getIndexForFieldID(fieldID))
455 auto subRef = fieldRef.getSubField(subID);
456 auto subOriginal = original.getSubField(subID);
457 auto value = subindex.getResult();
458 workStack.emplace_back(subOriginal, subRef,
value, fieldID - subID);
459 }
else if (
auto connect = dyn_cast<FConnectLike>(user)) {
461 if (
connect.getDest() != current)
479 if (LLVM_UNLIKELY(!
value))
483 auto *op =
value.getDefiningOp();
490 return TypeSwitch<Operation *, FieldRef>(op)
491 .Case<RefCastOp, ConstCastOp, UninferredResetCastOp>(
492 [lookThroughCasts](
auto op) {
493 if (!lookThroughCasts)
497 .Case<SubfieldOp, OpenSubfieldOp, SubindexOp, OpenSubindexOp, RefSubOp,
499 [](
auto subOp) {
return subOp.getAccessedField(); })
504 bool lookThroughCasts) {
505 if (LLVM_UNLIKELY(!
value))
515 id = deltaRef.getSubField(
id).getFieldID();
517 value = deltaRef.getValue();
525 if (
auto arg = dyn_cast<BlockArgument>(
value)) {
527 auto *op = arg.getOwner()->getParentOp();
528 TypeSwitch<Operation *>(op).Case<FModuleOp, ClassOp>([&](
auto op) {
529 auto name = cast<StringAttr>(op.getPortNames()[arg.getArgNumber()]);
530 string += name.getValue();
535 auto *op =
value.getDefiningOp();
536 TypeSwitch<Operation *>(op)
537 .Case<ObjectOp>([&](ObjectOp op) {
538 string += op.getInstanceName();
541 .Case<InstanceOp, MemOp>([&](
auto op) {
542 string += op.getName();
543 string += nameSafe ?
"_" :
".";
544 string += op.getPortName(cast<OpResult>(
value).getResultNumber())
548 .Case<FNamableOp>([&](
auto op) {
549 string += op.getName();
552 .Case<mlir::UnrealizedConversionCastOp>(
553 [&](mlir::UnrealizedConversionCastOp cast) {
555 if (cast.getNumResults() == 1 && cast.getNumOperands() == 1 &&
556 cast.getResult(0).getType() == cast.getOperand(0).getType()) {
557 value = cast.getInputs()[0];
572 std::pair<std::string, bool>
574 SmallString<64> name;
577 bool rootKnown = !name.empty();
579 auto type =
value.getType();
583 if (
auto refTy = type_dyn_cast<RefType>(type))
584 type = refTy.getType();
586 if (
auto bundleType = type_dyn_cast<BundleType>(type)) {
587 auto index = bundleType.getIndexForFieldID(localID);
589 auto &element = bundleType.getElements()[index];
591 name += nameSafe ?
"_" :
".";
592 name += element.name.getValue();
595 localID = localID - bundleType.getFieldID(index);
596 }
else if (
auto bundleType = type_dyn_cast<OpenBundleType>(type)) {
597 auto index = bundleType.getIndexForFieldID(localID);
599 auto &element = bundleType.getElements()[index];
601 name += nameSafe ?
"_" :
".";
602 name += element.name.getValue();
605 localID = localID - bundleType.getFieldID(index);
606 }
else if (
auto vecType = type_dyn_cast<FVectorType>(type)) {
607 auto index = vecType.getIndexForFieldID(localID);
608 name += nameSafe ?
"_" :
"[";
609 name += std::to_string(index);
613 type = vecType.getElementType();
614 localID = localID - vecType.getFieldID(index);
615 }
else if (
auto vecType = type_dyn_cast<OpenVectorType>(type)) {
616 auto index = vecType.getIndexForFieldID(localID);
617 name += nameSafe ?
"_" :
"[";
618 name += std::to_string(index);
622 type = vecType.getElementType();
623 localID = localID - vecType.getFieldID(index);
624 }
else if (
auto enumType = type_dyn_cast<FEnumType>(type)) {
625 auto index = enumType.getIndexForFieldID(localID);
626 auto &element = enumType.getElements()[index];
627 name += nameSafe ?
"_" :
".";
628 name += element.name.getValue();
630 localID = localID - enumType.getFieldID(index);
631 }
else if (
auto classType = type_dyn_cast<ClassType>(type)) {
632 auto index = classType.getIndexForFieldID(localID);
633 auto &element = classType.getElement(index);
634 name += nameSafe ?
"_" :
".";
635 name += element.name.getValue();
637 localID = localID - classType.getFieldID(index);
643 llvm_unreachable(
"unsupported type");
647 return {name.str().str(), rootKnown};
655 Value
value,
unsigned fieldID) {
657 while (fieldID != 0) {
659 .
Case<BundleType, OpenBundleType>([&](
auto bundle) {
660 auto index = bundle.getIndexForFieldID(fieldID);
662 fieldID -= bundle.getFieldID(index);
664 .Case<FVectorType, OpenVectorType>([&](
auto vector) {
665 auto index = vector.getIndexForFieldID(fieldID);
667 fieldID -= vector.getFieldID(index);
669 .Case<RefType>([&](
auto reftype) {
671 .template Case<BundleType, FVectorType>([&](
auto type) {
672 auto index = type.getIndexForFieldID(fieldID);
674 fieldID -= type.getFieldID(index);
676 .Default([&](
auto _) {
677 llvm::report_fatal_error(
678 "unrecognized type for indexing through with fieldID");
682 .Default([&](
auto _) {
683 llvm::report_fatal_error(
684 "unrecognized type for indexing through with fieldID");
704 return fn(0, type,
false);
706 uint64_t fieldID = 0;
707 auto recurse = [&](
auto &&f,
FIRRTLBaseType type,
bool isFlip) ->
void {
709 .
Case<BundleType>([&](BundleType bundle) {
710 for (
size_t i = 0, e = bundle.getNumElements(); i < e; ++i) {
712 f(f, bundle.getElementType(i),
713 isFlip ^ bundle.getElement(i).isFlip);
716 .
template Case<FVectorType>([&](FVectorType vector) {
717 for (
size_t i = 0, e = vector.getNumElements(); i < e; ++i) {
719 f(f, vector.getElementType(), isFlip);
722 .
template Case<FEnumType>([&](FEnumType fenum) {
723 for (
size_t i = 0, e = fenum.getNumElements(); i < e; ++i) {
725 f(f, fenum.getElementType(i), isFlip);
729 assert(groundType.isGround() &&
730 "only ground types are expected here");
731 fn(fieldID, groundType, isFlip);
734 recurse(recurse, type,
false);
741 if (
auto arg = dyn_cast<BlockArgument>(root)) {
742 auto mod = cast<FModuleLike>(arg.getOwner()->getParentOp());
750 MLIRContext *context, hw::InnerSymAttr attr, uint64_t fieldID,
752 SmallVector<hw::InnerSymPropertiesAttr> props;
755 if (
auto sym = attr.getSymIfExists(fieldID))
757 llvm::append_range(props, attr.getProps());
767 [](
auto &p,
auto &q) {
return p.getFieldID() < q.getFieldID(); });
775 if (
auto mod = dyn_cast<FModuleOp>(target.
getOp())) {
776 auto portIdx = target.
getPort();
777 assert(portIdx < mod.getNumPorts());
781 mod.setPortSymbolsAttr(portIdx, attr);
786 if (
auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(target.
getOp())) {
790 symOp.setInnerSymbolAttr(attr);
795 assert(0 &&
"target must be port of FModuleOp or InnerSymbol");
803 module = cast<FModuleLike>(target.
getOp());
805 module = target.
getOp()->getParentOfType<FModuleOp>();
809 return getNamespace(module);
818 auto mod = target.
isPort() ? dyn_cast<FModuleOp>(target.
getOp())
819 : target.
getOp()->getParentOfType<FModuleOp>();
821 "must be an operation inside an FModuleOp or port of FModuleOp");
827 std::pair<bool, std::optional<mlir::LocationAttr>>
829 StringAttr &locatorFilenameCache,
830 FileLineColLoc &fileLineColLocCache,
831 MLIRContext *context) {
833 if (!spelling.startswith(
"@[") || !spelling.endswith(
"]"))
834 return {
false, std::nullopt};
836 spelling = spelling.drop_front(2).drop_back(1);
840 auto decodeLocator = [&](StringRef input,
unsigned &resultLineNo,
841 unsigned &resultColNo) -> StringRef {
843 auto spaceLoc = input.find_last_of(
' ');
844 if (spaceLoc == StringRef::npos)
847 auto filename = input.take_front(spaceLoc);
848 auto lineAndColumn = input.drop_front(spaceLoc + 1);
852 StringRef lineStr, colStr;
853 std::tie(lineStr, colStr) = lineAndColumn.split(
':');
856 if (lineStr.getAsInteger(10, resultLineNo))
858 if (!colStr.empty()) {
859 if (colStr.front() !=
'{') {
860 if (colStr.getAsInteger(10, resultColNo))
864 if (colStr.drop_front().split(
',').first.getAsInteger(10, resultColNo))
872 unsigned lineNo = 0, columnNo = 0;
873 StringRef filename = decodeLocator(spelling, lineNo, columnNo);
874 if (filename.empty())
875 return {
false, std::nullopt};
880 return {
true, std::nullopt};
884 auto getFileLineColLoc = [&](StringRef filename,
unsigned lineNo,
885 unsigned columnNo) -> FileLineColLoc {
887 StringAttr filenameId = locatorFilenameCache;
888 if (filenameId.str() != filename) {
890 locatorFilenameCache = filenameId =
StringAttr::get(context, filename);
894 return fileLineColLocCache =
899 auto result = fileLineColLocCache;
900 if (result && result.getLine() == lineNo && result.getColumn() == columnNo)
903 return fileLineColLocCache =
915 SmallVector<Location> extraLocs;
916 auto spaceLoc = filename.find_last_of(
' ');
917 while (spaceLoc != StringRef::npos) {
920 unsigned nextLineNo = 0, nextColumnNo = 0;
922 decodeLocator(filename.take_front(spaceLoc), nextLineNo, nextColumnNo);
925 if (nextFilename.empty())
931 getFileLineColLoc(filename.drop_front(spaceLoc + 1), lineNo, columnNo);
932 extraLocs.push_back(loc);
933 filename = nextFilename;
935 columnNo = nextColumnNo;
936 spaceLoc = filename.find_last_of(
' ');
939 mlir::LocationAttr result = getFileLineColLoc(filename, lineNo, columnNo);
940 if (!extraLocs.empty()) {
941 extraLocs.push_back(result);
942 std::reverse(extraLocs.begin(), extraLocs.end());
945 return {
true, result};
952 Type type, std::optional<Location> loc,
953 llvm::function_ref<hw::TypeAliasType(Type, BaseTypeAliasType, Location)>
955 auto firType = type_dyn_cast<FIRRTLBaseType>(type);
961 if (BaseTypeAliasType aliasType = dyn_cast<BaseTypeAliasType>(firType)) {
964 type =
lowerType(aliasType.getInnerType(), loc, getTypeDeclFn);
965 return getTypeDeclFn(type, aliasType, *loc);
968 firType = firType.getPassiveType();
970 if (
auto bundle = type_dyn_cast<BundleType>(firType)) {
971 mlir::SmallVector<hw::StructType::FieldInfo, 8> hwfields;
972 for (
auto element : bundle) {
973 Type etype =
lowerType(element.type, loc, getTypeDeclFn);
976 hwfields.push_back(hw::StructType::FieldInfo{element.name, etype});
980 if (
auto vec = type_dyn_cast<FVectorType>(firType)) {
981 auto elemTy =
lowerType(vec.getElementType(), loc, getTypeDeclFn);
986 if (
auto fenum = type_dyn_cast<FEnumType>(firType)) {
987 mlir::SmallVector<hw::UnionType::FieldInfo, 8> hwfields;
988 SmallVector<Attribute> names;
990 for (
auto element : fenum) {
991 Type etype =
lowerType(element.type, loc, getTypeDeclFn);
994 hwfields.push_back(hw::UnionType::FieldInfo{element.name, etype, 0});
995 names.push_back(element.name);
996 if (!isa<UIntType>(element.type) ||
997 element.type.getBitWidthOrSentinel() != 0)
1005 hw::StructType::FieldInfo fields[2] = {
1010 if (type_isa<ClockType>(firType))
1013 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 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.
This file defines an intermediate representation for circuits acting as an abstraction for constraint...