22 #include "mlir/IR/Threading.h"
23 #include "llvm/ADT/APSInt.h"
24 #include "llvm/ADT/TinyPtrVector.h"
25 #include "llvm/Support/Debug.h"
26 #include "llvm/Support/ScopedPrinter.h"
28 using namespace circt;
29 using namespace firrtl;
31 #define DEBUG_TYPE "IMCP"
35 return isa<WireOp, RegResetOp, RegOp>(op);
40 return isa<SubindexOp, SubaccessOp, SubfieldOp, OpenSubfieldOp,
41 OpenSubindexOp, RefSubOp>(op);
47 return isa<NodeOp, RefResolveOp, RefSendOp>(op);
56 if (type_isa<RefType>(op->getResult(0).getType()))
90 LatticeValue() : valueAndTag(nullptr, Kind::Unknown) {}
92 LatticeValue(IntegerAttr attr)
93 : valueAndTag(attr, Kind::Constant) {}
94 LatticeValue(StringAttr attr)
95 : valueAndTag(attr, Kind::Constant) {}
97 static LatticeValue getOverdefined() {
99 result.markOverdefined();
103 bool isUnknown()
const {
return valueAndTag.getInt() == Kind::Unknown; }
104 bool isConstant()
const {
return valueAndTag.getInt() == Kind::Constant; }
105 bool isOverdefined()
const {
106 return valueAndTag.getInt() == Kind::Overdefined;
110 void markOverdefined() {
111 valueAndTag.setPointerAndInt(
nullptr, Kind::Overdefined);
115 void markConstant(IntegerAttr
value) {
116 valueAndTag.setPointerAndInt(
value, Kind::Constant);
121 Attribute getValue()
const {
return valueAndTag.getPointer(); }
131 bool mergeIn(LatticeValue rhs) {
133 if (isOverdefined() || rhs.isUnknown())
138 valueAndTag = rhs.valueAndTag;
145 if (valueAndTag != rhs.valueAndTag) {
152 bool operator==(
const LatticeValue &other)
const {
153 return valueAndTag == other.valueAndTag;
155 bool operator!=(
const LatticeValue &other)
const {
156 return valueAndTag != other.valueAndTag;
162 llvm::PointerIntPair<Attribute, 2, Kind> valueAndTag;
168 const LatticeValue &lattice) {
169 if (lattice.isUnknown())
170 return os <<
"<Unknown>";
171 if (lattice.isOverdefined())
172 return os <<
"<Overdefined>";
173 return os <<
"<" << lattice.getConstant() <<
">";
177 struct IMConstPropPass :
public IMConstPropBase<IMConstPropPass> {
179 void runOnOperation()
override;
180 void rewriteModuleBody(FModuleOp module);
183 bool isBlockExecutable(Block *block)
const {
184 return executableBlocks.count(block);
188 auto it = latticeValues.find(
value);
189 return it != latticeValues.end() && it->second.isOverdefined();
194 void markOverdefined(Value
value) {
196 auto firrtlType = type_dyn_cast<FIRRTLType>(
value.getType());
197 if (!firrtlType || type_isa<PropertyType>(firrtlType)) {
198 markOverdefined(fieldRef);
210 auto &entry = latticeValues[
value];
211 if (!entry.isOverdefined()) {
216 entry.markOverdefined();
217 changedLatticeValueWorklist.push_back(
value);
224 void mergeLatticeValue(
FieldRef value, LatticeValue &valueEntry,
225 LatticeValue source) {
226 if (valueEntry.mergeIn(source)) {
229 <<
"Changed to " << valueEntry <<
" : (" <<
value <<
")\n";
231 changedLatticeValueWorklist.push_back(
value);
235 void mergeLatticeValue(
FieldRef value, LatticeValue source) {
237 if (source.isUnknown())
239 mergeLatticeValue(
value, latticeValues[
value], source);
245 auto it = latticeValues.find(from);
246 if (it == latticeValues.end())
248 mergeLatticeValue(result, it->second);
251 void mergeLatticeValue(Value result, Value from) {
252 FieldRef fieldRefFrom = getOrCacheFieldRefFromValue(from);
253 FieldRef fieldRefResult = getOrCacheFieldRefFromValue(result);
254 if (!type_isa<FIRRTLType>(result.getType()))
255 return mergeLatticeValue(fieldRefResult, fieldRefFrom);
257 if (type_isa<PropertyType>(result.getType()))
258 return mergeLatticeValue(fieldRefResult, fieldRefFrom);
260 [&](uint64_t fieldID,
auto,
auto) {
261 mergeLatticeValue(fieldRefResult.getSubField(fieldID),
262 fieldRefFrom.getSubField(fieldID));
273 if (source.isUnknown())
277 auto &valueEntry = latticeValues[
value];
278 if (valueEntry != source) {
279 changedLatticeValueWorklist.push_back(
value);
290 auto &fieldRef = valueToFieldRef[
value];
300 bool allowTruncation =
false);
303 void markBlockExecutable(Block *block);
304 void markWireOp(WireOp wireOrReg);
305 void markMemOp(MemOp mem);
307 void markInvalidValueOp(InvalidValueOp invalid);
308 void markAggregateConstantOp(AggregateConstantOp constant);
309 void markInstanceOp(InstanceOp instance);
310 void markObjectOp(ObjectOp
object);
311 template <
typename OpTy>
312 void markConstantValueOp(OpTy op);
315 void visitRefSend(RefSendOp send,
FieldRef changedFieldRef);
316 void visitRefResolve(RefResolveOp resolve,
FieldRef changedFieldRef);
317 void mergeOnlyChangedLatticeValue(Value dest, Value src,
319 void visitNode(NodeOp node,
FieldRef changedFieldRef);
320 void visitOperation(Operation *op,
FieldRef changedFieldRef);
327 DenseMap<FieldRef, LatticeValue> latticeValues;
330 SmallPtrSet<Block *, 16> executableBlocks;
334 SmallVector<FieldRef, 64> changedLatticeValueWorklist;
337 DenseMap<FieldRef, llvm::TinyPtrVector<Operation *>> fieldRefToUsers;
341 llvm::DenseMap<Value, FieldRef> valueToFieldRef;
345 DenseMap<BlockArgument, llvm::TinyPtrVector<Value>>
346 resultPortToInstanceResultMapping;
356 void IMConstPropPass::runOnOperation() {
357 auto circuit = getOperation();
359 { logger.startLine() <<
"IMConstProp : " << circuit.getName() <<
"\n"; });
361 instanceGraph = &getAnalysis<InstanceGraph>();
364 for (
auto module : circuit.getBodyBlock()->getOps<FModuleOp>()) {
365 if (module.isPublic()) {
366 markBlockExecutable(module.getBodyBlock());
367 for (
auto port : module.getBodyBlock()->getArguments())
368 markOverdefined(port);
373 while (!changedLatticeValueWorklist.empty()) {
374 FieldRef changedFieldRef = changedLatticeValueWorklist.pop_back_val();
375 for (Operation *user : fieldRefToUsers[changedFieldRef]) {
376 if (isBlockExecutable(user->getBlock()))
377 visitOperation(user, changedFieldRef);
382 mlir::parallelForEach(circuit.getContext(),
383 circuit.getBodyBlock()->getOps<FModuleOp>(),
384 [&](
auto op) { rewriteModuleBody(op); });
387 instanceGraph =
nullptr;
388 latticeValues.clear();
389 executableBlocks.clear();
390 assert(changedLatticeValueWorklist.empty());
391 fieldRefToUsers.clear();
392 valueToFieldRef.clear();
393 resultPortToInstanceResultMapping.clear();
399 LatticeValue IMConstPropPass::getExtendedLatticeValue(
FieldRef value,
401 bool allowTruncation) {
403 auto it = latticeValues.find(
value);
404 if (it == latticeValues.end())
405 return LatticeValue();
407 auto result = it->second;
409 if (result.isUnknown() || result.isOverdefined())
413 if (isa<PropertyType>(destType))
416 auto constant = result.getConstant();
419 auto intAttr = dyn_cast<IntegerAttr>(constant);
420 assert(intAttr &&
"unsupported lattice attribute kind");
425 if (
auto boolAttr = dyn_cast<BoolAttr>(intAttr))
431 return LatticeValue::getOverdefined();
434 auto resultConstant = intAttr.getAPSInt();
435 auto destWidth = baseType.getBitWidthOrSentinel();
437 return LatticeValue::getOverdefined();
438 if (resultConstant.getBitWidth() == (
unsigned)destWidth)
443 return LatticeValue(
IntegerAttr::get(destType.getContext(), resultConstant));
450 void IMConstPropPass::markBlockExecutable(Block *block) {
451 if (!executableBlocks.insert(block).second)
456 for (
auto ba : block->getArguments())
460 for (
auto &op : *block) {
462 TypeSwitch<Operation *>(&op)
463 .Case<RegOp, RegResetOp>(
464 [&](
auto reg) { markOverdefined(op.getResult(0)); })
465 .Case<WireOp>([&](
auto wire) { markWireOp(wire); })
466 .Case<ConstantOp, SpecialConstantOp, StringConstantOp,
467 FIntegerConstantOp, BoolConstantOp>(
468 [&](
auto constOp) { markConstantValueOp(constOp); })
469 .Case<AggregateConstantOp>(
470 [&](
auto aggConstOp) { markAggregateConstantOp(aggConstOp); })
471 .Case<InvalidValueOp>(
472 [&](
auto invalid) { markInvalidValueOp(invalid); })
473 .Case<InstanceOp>([&](
auto instance) { markInstanceOp(instance); })
474 .Case<ObjectOp>([&](
auto obj) { markObjectOp(obj); })
475 .Case<MemOp>([&](
auto mem) { markMemOp(mem); })
476 .Default([&](
auto _) {
477 if (isa<mlir::UnrealizedConversionCastOp, VerbatimExprOp,
478 VerbatimWireOp, SubaccessOp>(op) ||
479 op.getNumOperands() == 0) {
483 for (
auto result : op.getResults())
484 markOverdefined(result);
496 bool hasAggregateOperand =
497 llvm::any_of(op.getOperandTypes(), [](Type type) {
498 return type_isa<FVectorType, BundleType>(type);
501 for (
auto result : op.getResults())
502 if (hasAggregateOperand ||
503 type_isa<FVectorType, BundleType>(result.getType()))
504 markOverdefined(result);
511 for (
auto operand : op.getOperands()) {
512 auto fieldRef = getOrCacheFieldRefFromValue(operand);
513 auto firrtlType = type_dyn_cast<FIRRTLType>(operand.getType());
517 if (type_isa<PropertyType>(firrtlType)) {
518 fieldRefToUsers[fieldRef].push_back(&op);
522 fieldRefToUsers[fieldRef.
getSubField(fieldID)].push_back(&op);
530 void IMConstPropPass::markWireOp(WireOp wire) {
531 auto type = type_dyn_cast<FIRRTLType>(wire.getResult().getType());
532 if (!type ||
hasDontTouch(wire.getResult()) || wire.isForceable()) {
533 for (
auto result : wire.getResults())
534 markOverdefined(result);
541 void IMConstPropPass::markMemOp(MemOp mem) {
542 for (
auto result : mem.getResults())
543 markOverdefined(result);
546 template <
typename OpTy>
547 void IMConstPropPass::markConstantValueOp(OpTy op) {
548 mergeLatticeValue(getOrCacheFieldRefFromValue(op),
549 LatticeValue(op.getValueAttr()));
552 void IMConstPropPass::markAggregateConstantOp(AggregateConstantOp constant) {
553 walkGroundTypes(constant.getType(), [&](uint64_t fieldID,
auto,
auto) {
554 mergeLatticeValue(FieldRef(constant, fieldID),
555 LatticeValue(cast<IntegerAttr>(
556 constant.getAttributeFromFieldID(fieldID))));
560 void IMConstPropPass::markInvalidValueOp(InvalidValueOp invalid) {
561 markOverdefined(invalid.getResult());
566 void IMConstPropPass::markInstanceOp(InstanceOp instance) {
568 Operation *op = instanceGraph->getReferencedModule(instance);
572 if (!isa<FModuleOp>(op)) {
573 auto module = dyn_cast<FModuleLike>(op);
574 for (
size_t resultNo = 0, e = instance.getNumResults(); resultNo != e;
576 auto portVal = instance.getResult(resultNo);
582 markOverdefined(portVal);
588 auto fModule = cast<FModuleOp>(op);
589 markBlockExecutable(fModule.getBodyBlock());
593 for (
size_t resultNo = 0, e = instance.getNumResults(); resultNo != e;
595 auto instancePortVal = instance.getResult(resultNo);
603 BlockArgument modulePortVal = fModule.getArgument(resultNo);
605 resultPortToInstanceResultMapping[modulePortVal].push_back(instancePortVal);
609 mergeLatticeValue(instancePortVal, modulePortVal);
613 void IMConstPropPass::markObjectOp(ObjectOp obj) {
615 markOverdefined(obj);
618 static std::optional<uint64_t>
621 assert(!type_isa<RefType>(connectionType));
632 void IMConstPropPass::mergeOnlyChangedLatticeValue(Value dest, Value src,
636 auto destType = dest.getType();
637 if (
auto refType = type_dyn_cast<RefType>(destType))
638 destType = refType.getType();
640 if (!isa<FIRRTLType>(destType)) {
643 markOverdefined(src);
644 return markOverdefined(dest);
647 auto fieldRefSrc = getOrCacheFieldRefFromValue(src);
648 auto fieldRefDest = getOrCacheFieldRefFromValue(dest);
652 if (
auto srcOffset =
getFieldIDOffset(changedFieldRef, destType, fieldRefSrc))
653 mergeLatticeValue(fieldRefDest.getSubField(*srcOffset),
654 fieldRefSrc.getSubField(*srcOffset));
658 if (
auto destOffset =
660 mergeLatticeValue(fieldRefDest.getSubField(*destOffset),
661 fieldRefSrc.getSubField(*destOffset));
664 void IMConstPropPass::visitConnectLike(FConnectLike
connect,
667 auto destType =
connect.getDest().getType();
668 if (
auto refType = type_dyn_cast<RefType>(destType))
669 destType = refType.getType();
672 if (!isa<FIRRTLType>(destType)) {
673 markOverdefined(
connect.getSrc());
674 return markOverdefined(
connect.getDest());
677 auto fieldRefSrc = getOrCacheFieldRefFromValue(
connect.getSrc());
678 auto fieldRefDest = getOrCacheFieldRefFromValue(
connect.getDest());
679 if (
auto subaccess = fieldRefDest.getValue().getDefiningOp<SubaccessOp>()) {
683 Value parent = subaccess.getInput();
684 while (parent.getDefiningOp() &&
685 parent.getDefiningOp()->getNumOperands() > 0)
686 parent = parent.getDefiningOp()->getOperand(0);
687 return markOverdefined(parent);
690 auto propagateElementLattice = [&](uint64_t fieldID,
FIRRTLType destType) {
691 auto fieldRefDestConnected = fieldRefDest.getSubField(fieldID);
692 assert(!firrtl::type_isa<FIRRTLBaseType>(destType) ||
693 firrtl::type_cast<FIRRTLBaseType>(destType).isGround());
697 getExtendedLatticeValue(fieldRefSrc.getSubField(fieldID), destType);
698 if (srcValue.isUnknown())
703 if (
auto blockArg = dyn_cast<BlockArgument>(fieldRefDest.getValue())) {
704 for (
auto userOfResultPort : resultPortToInstanceResultMapping[blockArg])
706 FieldRef(userOfResultPort, fieldRefDestConnected.getFieldID()),
709 return mergeLatticeValue(fieldRefDestConnected, srcValue);
712 auto dest = fieldRefDest.getValue().cast<mlir::OpResult>();
717 return mergeLatticeValue(fieldRefDestConnected, srcValue);
721 if (
auto instance = dest.getDefiningOp<InstanceOp>()) {
723 mergeLatticeValue(fieldRefDestConnected, srcValue);
725 dyn_cast<FModuleOp>(*instanceGraph->getReferencedModule(instance));
729 BlockArgument modulePortVal = module.getArgument(dest.getResultNumber());
731 return mergeLatticeValue(
732 FieldRef(modulePortVal, fieldRefDestConnected.getFieldID()),
738 if (dest.getDefiningOp<MemOp>())
742 if (isa_and_nonnull<ObjectSubfieldOp>(dest.getDefiningOp()))
745 connect.emitError(
"connectlike operation unhandled by IMConstProp")
746 .attachNote(
connect.getDest().getLoc())
747 <<
"connect destination is here";
750 if (
auto srcOffset =
getFieldIDOffset(changedFieldRef, destType, fieldRefSrc))
751 propagateElementLattice(
753 firrtl::type_cast<FIRRTLType>(
756 if (
auto relativeDest =
758 propagateElementLattice(
760 firrtl::type_cast<FIRRTLType>(
764 void IMConstPropPass::visitRefSend(RefSendOp send,
FieldRef changedFieldRef) {
766 return mergeOnlyChangedLatticeValue(send.getResult(), send.getBase(),
770 void IMConstPropPass::visitRefResolve(RefResolveOp resolve,
774 return mergeOnlyChangedLatticeValue(resolve.getResult(), resolve.getRef(),
778 void IMConstPropPass::visitNode(NodeOp node,
FieldRef changedFieldRef) {
779 if (
hasDontTouch(node.getResult()) || node.isForceable()) {
780 for (
auto result : node.getResults())
781 markOverdefined(result);
785 return mergeOnlyChangedLatticeValue(node.getResult(), node.getInput(),
795 void IMConstPropPass::visitOperation(Operation *op,
FieldRef changedField) {
797 if (
auto connectLikeOp = dyn_cast<FConnectLike>(op))
798 return visitConnectLike(connectLikeOp, changedField);
799 if (
auto sendOp = dyn_cast<RefSendOp>(op))
800 return visitRefSend(sendOp, changedField);
801 if (
auto resolveOp = dyn_cast<RefResolveOp>(op))
802 return visitRefResolve(resolveOp, changedField);
803 if (
auto nodeOp = dyn_cast<NodeOp>(op))
804 return visitNode(nodeOp, changedField);
815 auto isOverdefinedFn = [&](Value
value) {
816 return isOverdefined(getOrCacheFieldRefFromValue(
value));
818 if (llvm::all_of(op->getResults(), isOverdefinedFn))
823 if (op->getNumOperands() > 128) {
824 for (
auto value : op->getResults())
825 markOverdefined(
value);
831 SmallVector<Attribute, 8> operandConstants;
832 operandConstants.reserve(op->getNumOperands());
833 bool hasUnknown =
false;
834 for (Value operand : op->getOperands()) {
836 auto &operandLattice = latticeValues[getOrCacheFieldRefFromValue(operand)];
841 if (operandLattice.isUnknown())
846 if (operandLattice.isConstant())
847 operandConstants.push_back(operandLattice.getValue());
849 operandConstants.push_back({});
854 SmallVector<OpFoldResult, 8> foldResults;
855 foldResults.reserve(op->getNumResults());
856 if (failed(op->fold(operandConstants, foldResults))) {
858 logger.startLine() <<
"Folding Failed operation : '" << op->getName()
864 for (
auto value : op->getResults())
865 markOverdefined(
value);
870 logger.getOStream() <<
"\n";
871 logger.startLine() <<
"Folding operation : '" << op->getName() <<
"\n";
873 logger.getOStream() <<
"( ";
874 for (
auto cst : operandConstants)
876 logger.getOStream() <<
"{} ";
878 logger.getOStream() << cst <<
" ";
880 logger.getOStream() <<
") -> { ";
882 for (
auto &r : foldResults) {
883 logger.getOStream() << r <<
" ";
886 logger.getOStream() <<
"}\n";
893 if (foldResults.empty())
894 return visitOperation(op, changedField);
897 assert(foldResults.size() == op->getNumResults() &&
"invalid result size");
898 for (
unsigned i = 0, e = foldResults.size(); i != e; ++i) {
900 LatticeValue resultLattice;
901 OpFoldResult foldResult = foldResults[i];
902 if (Attribute foldAttr = dyn_cast<Attribute>(foldResult)) {
903 if (
auto intAttr = dyn_cast<IntegerAttr>(foldAttr))
904 resultLattice = LatticeValue(intAttr);
905 else if (
auto strAttr = dyn_cast<StringAttr>(foldAttr))
906 resultLattice = LatticeValue(strAttr);
908 resultLattice = LatticeValue::getOverdefined();
911 latticeValues[getOrCacheFieldRefFromValue(foldResult.get<Value>())];
914 mergeLatticeValue(getOrCacheFieldRefFromValue(op->getResult(i)),
919 void IMConstPropPass::rewriteModuleBody(FModuleOp module) {
920 auto *body = module.getBodyBlock();
922 if (!executableBlocks.count(body))
925 auto builder = OpBuilder::atBlockBegin(body);
929 auto cursor =
builder.create<firrtl::ConstantOp>(module.getLoc(), APSInt(1));
930 builder.setInsertionPoint(cursor);
933 DenseMap<std::pair<Attribute, Type>, Operation *> constPool;
935 std::function<Value(Attribute, Type, Location)> getConst =
936 [&](Attribute constantValue, Type type, Location loc) -> Value {
937 auto constIt = constPool.find({constantValue, type});
938 if (constIt != constPool.end()) {
939 auto *cst = constIt->second;
941 cst->setLoc(
builder.getFusedLoc({cst->getLoc(), loc}));
942 return cst->getResult(0);
944 OpBuilder::InsertionGuard x(
builder);
945 builder.setInsertionPoint(cursor);
950 if (
auto refType = type_dyn_cast<RefType>(type)) {
951 assert(!type_cast<RefType>(type).getForceable() &&
952 "Attempting to materialize rwprobe of constant, shouldn't happen");
953 auto inner = getConst(constantValue, refType.getType(), loc);
955 cst =
builder.create<RefSendOp>(loc, inner);
957 cst = module->getDialect()->materializeConstant(
builder, constantValue,
959 assert(cst &&
"all FIRRTL constants can be materialized");
960 constPool.insert({{constantValue, type}, cst});
961 return cst->getResult(0);
966 auto replaceValueIfPossible = [&](Value
value) ->
bool {
970 auto replaceIfNotConnect = [&
value](Value replacement) {
971 value.replaceUsesWithIf(replacement, [](OpOperand &operand) {
972 return !isa<FConnectLike>(operand.getOwner()) ||
973 operand.getOperandNumber() != 0;
978 auto it = latticeValues.find(getOrCacheFieldRefFromValue(
value));
979 if (it == latticeValues.end() || it->second.isOverdefined() ||
980 it->second.isUnknown())
986 if (!type_isa<FIRRTLBaseType, RefType, FIntegerType, StringType, BoolType>(
991 getConst(it->second.getValue(),
value.getType(),
value.getLoc());
993 replaceIfNotConnect(cstValue);
998 for (
auto &port : body->getArguments())
999 replaceValueIfPossible(port);
1007 bool aboveCursor =
false;
1008 for (
auto &op : llvm::make_early_inc_range(llvm::reverse(*body))) {
1009 auto dropIfDead = [&](Operation &op,
const Twine &debugPrefix) {
1010 if (op.use_empty() &&
1013 { logger.getOStream() << debugPrefix <<
" : " << op <<
"\n"; });
1023 dropIfDead(op,
"Trivially dead materialized constant");
1027 if (&op == cursor) {
1034 if (
auto connect = dyn_cast<FConnectLike>(op)) {
1035 if (
auto *destOp =
connect.getDest().getDefiningOp()) {
1036 auto fieldRef = getOrCacheFieldRefFromValue(
connect.getDest());
1042 auto type = type_dyn_cast<FIRRTLType>(
connect.getDest().getType());
1045 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
1046 if (baseType && !baseType.isGround())
1058 if (op.getNumResults() != 1 && !isa<InstanceOp>(op))
1062 if (dropIfDead(op,
"Trivially dead"))
1067 if (op.hasTrait<mlir::OpTrait::ConstantLike>())
1071 builder.setInsertionPoint(&op);
1072 bool foldedAny =
false;
1073 for (
auto result : op.getResults())
1074 foldedAny |= replaceValueIfPossible(result);
1080 if (foldedAny && dropIfDead(op,
"Made dead"))
1086 return std::make_unique<IMConstPropPass>();
assert(baseType &&"element must be base type")
static std::optional< APSInt > getConstant(Attribute operand)
Determine the value of a constant operand for the sake of constant folding.
static bool isNodeLike(Operation *op)
static std::optional< uint64_t > getFieldIDOffset(FieldRef changedFieldRef, Type connectionType, FieldRef connectedValueFieldRef)
static bool isWireOrReg(Operation *op)
Return true if this is a wire or register.
static bool isAggregate(Operation *op)
Return true if this is an aggregate indexer.
static bool isDeletableWireOrRegOrNode(Operation *op)
Return true if this is a wire or register we're allowed to delete.
bool operator!=(const ResetDomain &a, const ResetDomain &b)
bool operator==(const ResetDomain &a, const ResetDomain &b)
This class represents a reference to a specific field or element of an aggregate value.
FieldRef getSubField(unsigned subFieldID) const
Get a reference to a subfield.
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 canBeDeleted() const
Check if every annotation can be deleted.
This graph tracks modules and where they are instantiated.
def connect(destination, source)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
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.
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.
bool isConstant(Operation *op)
Return true if the specified operation has a constant value.
std::unique_ptr< mlir::Pass > createIMConstPropPass()
bool hasDontTouch(Value value)
Check whether a block argument ("port") or the operation defining a value has a DontTouch annotation,...
T & operator<<(T &os, FIRVersion version)
bool hasDroppableName(Operation *op)
Return true if the name is droppable.
std::pair< std::string, bool > getFieldName(const FieldRef &fieldRef, bool nameSafe=false)
Get a string identifier representing the FieldRef.
::mlir::Type getFinalTypeByFieldID(Type type, uint64_t fieldID)
uint64_t getMaxFieldID(Type)
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
APSInt extOrTruncZeroWidth(APSInt value, unsigned width)
A safe version of APSInt::extOrTrunc that will NOT assert on zero-width signed APSInts.
mlir::raw_indented_ostream & dbgs()
def reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)