21 #include "mlir/IR/Iterators.h"
22 #include "mlir/IR/Threading.h"
23 #include "mlir/Pass/Pass.h"
24 #include "llvm/ADT/APSInt.h"
25 #include "llvm/ADT/TinyPtrVector.h"
26 #include "llvm/Support/Debug.h"
27 #include "llvm/Support/ScopedPrinter.h"
31 #define GEN_PASS_DEF_IMCONSTPROP
32 #include "circt/Dialect/FIRRTL/Passes.h.inc"
36 using namespace circt;
37 using namespace firrtl;
39 #define DEBUG_TYPE "IMCP"
43 return isa<WireOp, RegResetOp, RegOp>(op);
48 return isa<SubindexOp, SubaccessOp, SubfieldOp, OpenSubfieldOp,
49 OpenSubindexOp, RefSubOp>(op);
55 return isa<NodeOp, RefResolveOp, RefSendOp>(op);
64 if (type_isa<RefType>(op->getResult(0).getType()))
98 LatticeValue() : valueAndTag(nullptr, Kind::Unknown) {}
100 LatticeValue(IntegerAttr attr)
101 : valueAndTag(attr, Kind::Constant) {}
102 LatticeValue(StringAttr attr)
103 : valueAndTag(attr, Kind::Constant) {}
105 static LatticeValue getOverdefined() {
107 result.markOverdefined();
111 bool isUnknown()
const {
return valueAndTag.getInt() == Kind::Unknown; }
112 bool isConstant()
const {
return valueAndTag.getInt() == Kind::Constant; }
113 bool isOverdefined()
const {
114 return valueAndTag.getInt() == Kind::Overdefined;
118 void markOverdefined() {
119 valueAndTag.setPointerAndInt(
nullptr, Kind::Overdefined);
123 void markConstant(IntegerAttr value) {
124 valueAndTag.setPointerAndInt(value, Kind::Constant);
129 Attribute getValue()
const {
return valueAndTag.getPointer(); }
139 bool mergeIn(LatticeValue rhs) {
141 if (isOverdefined() || rhs.isUnknown())
146 valueAndTag = rhs.valueAndTag;
153 if (valueAndTag != rhs.valueAndTag) {
160 bool operator==(
const LatticeValue &other)
const {
161 return valueAndTag == other.valueAndTag;
163 bool operator!=(
const LatticeValue &other)
const {
164 return valueAndTag != other.valueAndTag;
170 llvm::PointerIntPair<Attribute, 2, Kind> valueAndTag;
176 const LatticeValue &lattice) {
177 if (lattice.isUnknown())
178 return os <<
"<Unknown>";
179 if (lattice.isOverdefined())
180 return os <<
"<Overdefined>";
181 return os <<
"<" << lattice.getConstant() <<
">";
185 struct IMConstPropPass
186 :
public circt::firrtl::impl::IMConstPropBase<IMConstPropPass> {
188 void runOnOperation()
override;
189 void rewriteModuleBody(FModuleOp module);
192 bool isBlockExecutable(Block *block)
const {
193 return executableBlocks.count(block);
196 bool isOverdefined(
FieldRef value)
const {
197 auto it = latticeValues.find(value);
198 return it != latticeValues.end() && it->second.isOverdefined();
203 void markOverdefined(Value value) {
204 FieldRef fieldRef = getOrCacheFieldRefFromValue(value);
205 auto firrtlType = type_dyn_cast<FIRRTLType>(value.getType());
206 if (!firrtlType || type_isa<PropertyType>(firrtlType)) {
207 markOverdefined(fieldRef);
218 void markOverdefined(
FieldRef value) {
219 auto &entry = latticeValues[value];
220 if (!entry.isOverdefined()) {
223 <<
"Setting overdefined : (" <<
getFieldName(value).first <<
")\n";
225 entry.markOverdefined();
226 changedLatticeValueWorklist.push_back(value);
233 void mergeLatticeValue(
FieldRef value, LatticeValue &valueEntry,
234 LatticeValue source) {
235 if (valueEntry.mergeIn(source)) {
238 <<
"Changed to " << valueEntry <<
" : (" << value <<
")\n";
240 changedLatticeValueWorklist.push_back(value);
244 void mergeLatticeValue(
FieldRef value, LatticeValue source) {
246 if (source.isUnknown())
248 mergeLatticeValue(value, latticeValues[value], source);
254 auto it = latticeValues.find(from);
255 if (it == latticeValues.end())
257 mergeLatticeValue(result, it->second);
260 void mergeLatticeValue(Value result, Value from) {
261 FieldRef fieldRefFrom = getOrCacheFieldRefFromValue(from);
262 FieldRef fieldRefResult = getOrCacheFieldRefFromValue(result);
263 if (!type_isa<FIRRTLType>(result.getType()))
264 return mergeLatticeValue(fieldRefResult, fieldRefFrom);
266 if (type_isa<PropertyType>(result.getType()))
267 return mergeLatticeValue(fieldRefResult, fieldRefFrom);
269 [&](uint64_t fieldID,
auto,
auto) {
270 mergeLatticeValue(fieldRefResult.getSubField(fieldID),
271 fieldRefFrom.getSubField(fieldID));
280 void setLatticeValue(
FieldRef value, LatticeValue source) {
282 if (source.isUnknown())
286 auto &valueEntry = latticeValues[value];
287 if (valueEntry != source) {
288 changedLatticeValueWorklist.push_back(value);
296 FieldRef getOrCacheFieldRefFromValue(Value value) {
297 if (!value.getDefiningOp() || !
isAggregate(value.getDefiningOp()))
299 auto &fieldRef = valueToFieldRef[value];
309 bool allowTruncation =
false);
312 void markBlockExecutable(Block *block);
313 void markWireOp(WireOp wireOrReg);
314 void markMemOp(MemOp mem);
316 void markInvalidValueOp(InvalidValueOp invalid);
317 void markAggregateConstantOp(AggregateConstantOp constant);
318 void markInstanceOp(InstanceOp instance);
319 void markObjectOp(ObjectOp
object);
320 template <
typename OpTy>
321 void markConstantValueOp(OpTy op);
324 void visitRefSend(RefSendOp send,
FieldRef changedFieldRef);
325 void visitRefResolve(RefResolveOp resolve,
FieldRef changedFieldRef);
326 void mergeOnlyChangedLatticeValue(Value dest, Value src,
328 void visitNode(NodeOp node,
FieldRef changedFieldRef);
329 void visitOperation(Operation *op,
FieldRef changedFieldRef);
336 DenseMap<FieldRef, LatticeValue> latticeValues;
339 SmallPtrSet<Block *, 16> executableBlocks;
343 SmallVector<FieldRef, 64> changedLatticeValueWorklist;
346 DenseMap<FieldRef, llvm::TinyPtrVector<Operation *>> fieldRefToUsers;
350 llvm::DenseMap<Value, FieldRef> valueToFieldRef;
354 DenseMap<BlockArgument, llvm::TinyPtrVector<Value>>
355 resultPortToInstanceResultMapping;
359 llvm::ScopedPrinter logger{llvm::dbgs()};
365 void IMConstPropPass::runOnOperation() {
366 auto circuit = getOperation();
368 { logger.startLine() <<
"IMConstProp : " << circuit.getName() <<
"\n"; });
370 instanceGraph = &getAnalysis<InstanceGraph>();
373 for (
auto module : circuit.getBodyBlock()->getOps<FModuleOp>()) {
374 if (module.isPublic()) {
375 markBlockExecutable(module.getBodyBlock());
376 for (
auto port : module.getBodyBlock()->getArguments())
377 markOverdefined(port);
382 while (!changedLatticeValueWorklist.empty()) {
383 FieldRef changedFieldRef = changedLatticeValueWorklist.pop_back_val();
384 for (Operation *user : fieldRefToUsers[changedFieldRef]) {
385 if (isBlockExecutable(user->getBlock()))
386 visitOperation(user, changedFieldRef);
391 mlir::parallelForEach(circuit.getContext(),
392 circuit.getBodyBlock()->getOps<FModuleOp>(),
393 [&](
auto op) { rewriteModuleBody(op); });
396 instanceGraph =
nullptr;
397 latticeValues.clear();
398 executableBlocks.clear();
399 assert(changedLatticeValueWorklist.empty());
400 fieldRefToUsers.clear();
401 valueToFieldRef.clear();
402 resultPortToInstanceResultMapping.clear();
408 LatticeValue IMConstPropPass::getExtendedLatticeValue(
FieldRef value,
410 bool allowTruncation) {
412 auto it = latticeValues.find(value);
413 if (it == latticeValues.end())
414 return LatticeValue();
416 auto result = it->second;
418 if (result.isUnknown() || result.isOverdefined())
422 if (isa<PropertyType>(destType))
425 auto constant = result.getConstant();
428 auto intAttr = dyn_cast<IntegerAttr>(constant);
429 assert(intAttr &&
"unsupported lattice attribute kind");
434 if (
auto boolAttr = dyn_cast<BoolAttr>(intAttr))
440 return LatticeValue::getOverdefined();
443 auto resultConstant = intAttr.getAPSInt();
444 auto destWidth = baseType.getBitWidthOrSentinel();
446 return LatticeValue::getOverdefined();
447 if (resultConstant.getBitWidth() == (
unsigned)destWidth)
452 return LatticeValue(
IntegerAttr::get(destType.getContext(), resultConstant));
459 void IMConstPropPass::markBlockExecutable(Block *block) {
460 if (!executableBlocks.insert(block).second)
465 for (
auto ba : block->getArguments())
469 for (
auto &op : *block) {
471 TypeSwitch<Operation *>(&op)
472 .Case<RegOp, RegResetOp>(
473 [&](
auto reg) { markOverdefined(op.getResult(0)); })
474 .Case<WireOp>([&](
auto wire) { markWireOp(wire); })
475 .Case<ConstantOp, SpecialConstantOp, StringConstantOp,
476 FIntegerConstantOp, BoolConstantOp>(
477 [&](
auto constOp) { markConstantValueOp(constOp); })
478 .Case<AggregateConstantOp>(
479 [&](
auto aggConstOp) { markAggregateConstantOp(aggConstOp); })
480 .Case<InvalidValueOp>(
481 [&](
auto invalid) { markInvalidValueOp(invalid); })
482 .Case<InstanceOp>([&](
auto instance) { markInstanceOp(instance); })
483 .Case<ObjectOp>([&](
auto obj) { markObjectOp(obj); })
484 .Case<MemOp>([&](
auto mem) { markMemOp(mem); })
486 [&](
auto layer) { markBlockExecutable(layer.getBody(0)); })
487 .Default([&](
auto _) {
488 if (isa<mlir::UnrealizedConversionCastOp, VerbatimExprOp,
489 VerbatimWireOp, SubaccessOp>(op) ||
490 op.getNumOperands() == 0) {
494 for (
auto result : op.getResults())
495 markOverdefined(result);
507 bool hasAggregateOperand =
508 llvm::any_of(op.getOperandTypes(), [](Type type) {
509 return type_isa<FVectorType, BundleType>(type);
512 for (
auto result : op.getResults())
513 if (hasAggregateOperand ||
514 type_isa<FVectorType, BundleType>(result.getType()))
515 markOverdefined(result);
522 for (
auto operand : op.getOperands()) {
523 auto fieldRef = getOrCacheFieldRefFromValue(operand);
524 auto firrtlType = type_dyn_cast<FIRRTLType>(operand.getType());
528 if (type_isa<PropertyType>(firrtlType)) {
529 fieldRefToUsers[fieldRef].push_back(&op);
533 fieldRefToUsers[fieldRef.
getSubField(fieldID)].push_back(&op);
541 void IMConstPropPass::markWireOp(WireOp wire) {
542 auto type = type_dyn_cast<FIRRTLType>(wire.getResult().getType());
543 if (!type ||
hasDontTouch(wire.getResult()) || wire.isForceable()) {
544 for (
auto result : wire.getResults())
545 markOverdefined(result);
552 void IMConstPropPass::markMemOp(MemOp mem) {
553 for (
auto result : mem.getResults())
554 markOverdefined(result);
557 template <
typename OpTy>
558 void IMConstPropPass::markConstantValueOp(OpTy op) {
559 mergeLatticeValue(getOrCacheFieldRefFromValue(op),
560 LatticeValue(op.getValueAttr()));
563 void IMConstPropPass::markAggregateConstantOp(AggregateConstantOp constant) {
564 walkGroundTypes(constant.getType(), [&](uint64_t fieldID,
auto,
auto) {
565 mergeLatticeValue(FieldRef(constant, fieldID),
566 LatticeValue(cast<IntegerAttr>(
567 constant.getAttributeFromFieldID(fieldID))));
571 void IMConstPropPass::markInvalidValueOp(InvalidValueOp invalid) {
572 markOverdefined(invalid.getResult());
577 void IMConstPropPass::markInstanceOp(InstanceOp instance) {
579 Operation *op = instance.getReferencedModule(*instanceGraph);
583 if (!isa<FModuleOp>(op)) {
584 auto module = dyn_cast<FModuleLike>(op);
585 for (
size_t resultNo = 0, e = instance.getNumResults(); resultNo != e;
587 auto portVal = instance.getResult(resultNo);
593 markOverdefined(portVal);
599 auto fModule = cast<FModuleOp>(op);
600 markBlockExecutable(fModule.getBodyBlock());
604 for (
size_t resultNo = 0, e = instance.getNumResults(); resultNo != e;
606 auto instancePortVal = instance.getResult(resultNo);
614 BlockArgument modulePortVal = fModule.getArgument(resultNo);
616 resultPortToInstanceResultMapping[modulePortVal].push_back(instancePortVal);
620 mergeLatticeValue(instancePortVal, modulePortVal);
624 void IMConstPropPass::markObjectOp(ObjectOp obj) {
626 markOverdefined(obj);
629 static std::optional<uint64_t>
632 assert(!type_isa<RefType>(connectionType));
643 void IMConstPropPass::mergeOnlyChangedLatticeValue(Value dest, Value src,
647 auto destType = dest.getType();
648 if (
auto refType = type_dyn_cast<RefType>(destType))
649 destType = refType.getType();
651 if (!isa<FIRRTLType>(destType)) {
654 markOverdefined(src);
655 return markOverdefined(dest);
658 auto fieldRefSrc = getOrCacheFieldRefFromValue(src);
659 auto fieldRefDest = getOrCacheFieldRefFromValue(dest);
663 if (
auto srcOffset =
getFieldIDOffset(changedFieldRef, destType, fieldRefSrc))
664 mergeLatticeValue(fieldRefDest.getSubField(*srcOffset),
665 fieldRefSrc.getSubField(*srcOffset));
669 if (
auto destOffset =
671 mergeLatticeValue(fieldRefDest.getSubField(*destOffset),
672 fieldRefSrc.getSubField(*destOffset));
675 void IMConstPropPass::visitConnectLike(FConnectLike
connect,
678 auto destType =
connect.getDest().getType();
679 if (
auto refType = type_dyn_cast<RefType>(destType))
680 destType = refType.getType();
683 if (!isa<FIRRTLType>(destType)) {
684 markOverdefined(
connect.getSrc());
685 return markOverdefined(
connect.getDest());
688 auto fieldRefSrc = getOrCacheFieldRefFromValue(
connect.getSrc());
689 auto fieldRefDest = getOrCacheFieldRefFromValue(
connect.getDest());
690 if (
auto subaccess = fieldRefDest.getValue().getDefiningOp<SubaccessOp>()) {
694 Value parent = subaccess.getInput();
695 while (parent.getDefiningOp() &&
696 parent.getDefiningOp()->getNumOperands() > 0)
697 parent = parent.getDefiningOp()->getOperand(0);
698 return markOverdefined(parent);
701 auto propagateElementLattice = [&](uint64_t fieldID,
FIRRTLType destType) {
702 auto fieldRefDestConnected = fieldRefDest.getSubField(fieldID);
703 assert(!firrtl::type_isa<FIRRTLBaseType>(destType) ||
704 firrtl::type_cast<FIRRTLBaseType>(destType).isGround());
708 getExtendedLatticeValue(fieldRefSrc.getSubField(fieldID), destType);
709 if (srcValue.isUnknown())
714 if (
auto blockArg = dyn_cast<BlockArgument>(fieldRefDest.getValue())) {
715 for (
auto userOfResultPort : resultPortToInstanceResultMapping[blockArg])
717 FieldRef(userOfResultPort, fieldRefDestConnected.getFieldID()),
720 return mergeLatticeValue(fieldRefDestConnected, srcValue);
723 auto dest = cast<mlir::OpResult>(fieldRefDest.getValue());
728 return mergeLatticeValue(fieldRefDestConnected, srcValue);
732 if (
auto instance = dest.getDefiningOp<InstanceOp>()) {
734 mergeLatticeValue(fieldRefDestConnected, srcValue);
735 auto mod = instance.getReferencedModule<FModuleOp>(*instanceGraph);
739 BlockArgument modulePortVal = mod.getArgument(dest.getResultNumber());
741 return mergeLatticeValue(
742 FieldRef(modulePortVal, fieldRefDestConnected.getFieldID()),
748 if (dest.getDefiningOp<MemOp>())
752 if (isa_and_nonnull<ObjectSubfieldOp>(dest.getDefiningOp()))
755 connect.emitError(
"connectlike operation unhandled by IMConstProp")
756 .attachNote(
connect.getDest().getLoc())
757 <<
"connect destination is here";
760 if (
auto srcOffset =
getFieldIDOffset(changedFieldRef, destType, fieldRefSrc))
761 propagateElementLattice(
763 firrtl::type_cast<FIRRTLType>(
766 if (
auto relativeDest =
768 propagateElementLattice(
770 firrtl::type_cast<FIRRTLType>(
774 void IMConstPropPass::visitRefSend(RefSendOp send,
FieldRef changedFieldRef) {
776 return mergeOnlyChangedLatticeValue(send.getResult(), send.getBase(),
780 void IMConstPropPass::visitRefResolve(RefResolveOp resolve,
784 return mergeOnlyChangedLatticeValue(resolve.getResult(), resolve.getRef(),
788 void IMConstPropPass::visitNode(NodeOp node,
FieldRef changedFieldRef) {
789 if (
hasDontTouch(node.getResult()) || node.isForceable()) {
790 for (
auto result : node.getResults())
791 markOverdefined(result);
795 return mergeOnlyChangedLatticeValue(node.getResult(), node.getInput(),
805 void IMConstPropPass::visitOperation(Operation *op,
FieldRef changedField) {
807 if (
auto connectLikeOp = dyn_cast<FConnectLike>(op))
808 return visitConnectLike(connectLikeOp, changedField);
809 if (
auto sendOp = dyn_cast<RefSendOp>(op))
810 return visitRefSend(sendOp, changedField);
811 if (
auto resolveOp = dyn_cast<RefResolveOp>(op))
812 return visitRefResolve(resolveOp, changedField);
813 if (
auto nodeOp = dyn_cast<NodeOp>(op))
814 return visitNode(nodeOp, changedField);
825 auto isOverdefinedFn = [&](Value value) {
826 return isOverdefined(getOrCacheFieldRefFromValue(value));
828 if (llvm::all_of(op->getResults(), isOverdefinedFn))
833 if (op->getNumOperands() > 128) {
834 for (
auto value : op->getResults())
835 markOverdefined(value);
841 SmallVector<Attribute, 8> operandConstants;
842 operandConstants.reserve(op->getNumOperands());
843 bool hasUnknown =
false;
844 for (Value operand : op->getOperands()) {
846 auto &operandLattice = latticeValues[getOrCacheFieldRefFromValue(operand)];
851 if (operandLattice.isUnknown())
856 if (operandLattice.isConstant())
857 operandConstants.push_back(operandLattice.getValue());
859 operandConstants.push_back({});
864 SmallVector<OpFoldResult, 8> foldResults;
865 foldResults.reserve(op->getNumResults());
866 if (failed(op->fold(operandConstants, foldResults))) {
868 logger.startLine() <<
"Folding Failed operation : '" << op->getName()
874 for (
auto value : op->getResults())
875 markOverdefined(value);
880 logger.getOStream() <<
"\n";
881 logger.startLine() <<
"Folding operation : '" << op->getName() <<
"\n";
883 logger.getOStream() <<
"( ";
884 for (
auto cst : operandConstants)
886 logger.getOStream() <<
"{} ";
888 logger.getOStream() << cst <<
" ";
890 logger.getOStream() <<
") -> { ";
892 for (
auto &r : foldResults) {
893 logger.getOStream() << r <<
" ";
896 logger.getOStream() <<
"}\n";
903 if (foldResults.empty())
904 return visitOperation(op, changedField);
907 assert(foldResults.size() == op->getNumResults() &&
"invalid result size");
908 for (
unsigned i = 0, e = foldResults.size(); i != e; ++i) {
910 LatticeValue resultLattice;
911 OpFoldResult foldResult = foldResults[i];
912 if (Attribute foldAttr = dyn_cast<Attribute>(foldResult)) {
913 if (
auto intAttr = dyn_cast<IntegerAttr>(foldAttr))
914 resultLattice = LatticeValue(intAttr);
915 else if (
auto strAttr = dyn_cast<StringAttr>(foldAttr))
916 resultLattice = LatticeValue(strAttr);
918 resultLattice = LatticeValue::getOverdefined();
921 latticeValues[getOrCacheFieldRefFromValue(foldResult.get<Value>())];
924 mergeLatticeValue(getOrCacheFieldRefFromValue(op->getResult(i)),
929 void IMConstPropPass::rewriteModuleBody(FModuleOp module) {
930 auto *body = module.getBodyBlock();
932 if (!executableBlocks.count(body))
935 auto builder = OpBuilder::atBlockBegin(body);
939 auto cursor = builder.create<firrtl::ConstantOp>(module.getLoc(), APSInt(1));
940 builder.setInsertionPoint(cursor);
943 DenseMap<std::pair<Attribute, Type>, Operation *> constPool;
945 std::function<Value(Attribute, Type, Location)> getConst =
946 [&](Attribute constantValue, Type type, Location loc) -> Value {
947 auto constIt = constPool.find({constantValue, type});
948 if (constIt != constPool.end()) {
949 auto *cst = constIt->second;
951 cst->setLoc(builder.getFusedLoc({cst->getLoc(), loc}));
952 return cst->getResult(0);
954 OpBuilder::InsertionGuard x(builder);
955 builder.setInsertionPoint(cursor);
960 if (
auto refType = type_dyn_cast<RefType>(type)) {
961 assert(!type_cast<RefType>(type).getForceable() &&
962 "Attempting to materialize rwprobe of constant, shouldn't happen");
963 auto inner = getConst(constantValue, refType.getType(), loc);
965 cst = builder.create<RefSendOp>(loc, inner);
967 cst = module->getDialect()->materializeConstant(builder, constantValue,
969 assert(cst &&
"all FIRRTL constants can be materialized");
970 constPool.insert({{constantValue, type}, cst});
971 return cst->getResult(0);
976 auto replaceValueIfPossible = [&](Value value) ->
bool {
980 auto replaceIfNotConnect = [&value](Value replacement) {
981 value.replaceUsesWithIf(replacement, [](OpOperand &operand) {
982 return !isa<FConnectLike>(operand.getOwner()) ||
983 operand.getOperandNumber() != 0;
989 if (it == latticeValues.end() || it->second.isOverdefined() ||
990 it->second.isUnknown())
996 if (!type_isa<FIRRTLBaseType, RefType, FIntegerType, StringType, BoolType>(
1001 getConst(it->second.getValue(), value.getType(), value.
getLoc());
1003 replaceIfNotConnect(cstValue);
1008 for (
auto &port : body->getArguments())
1009 replaceValueIfPossible(port);
1017 bool aboveCursor =
false;
1018 module.walk<mlir::WalkOrder::PostOrder, mlir::ReverseIterator>(
1019 [&](Operation *op) {
1020 auto dropIfDead = [&](Operation *op,
const Twine &debugPrefix) {
1021 if (op->use_empty() &&
1024 { logger.getOStream() << debugPrefix <<
" : " << op <<
"\n"; });
1034 dropIfDead(op,
"Trivially dead materialized constant");
1035 return WalkResult::advance();
1041 return WalkResult::advance();
1045 if (
auto connect = dyn_cast<FConnectLike>(op)) {
1046 if (
auto *destOp =
connect.getDest().getDefiningOp()) {
1047 auto fieldRef = getOrCacheFieldRefFromValue(
connect.getDest());
1053 auto type = type_dyn_cast<FIRRTLType>(
connect.getDest().getType());
1055 return WalkResult::advance();
1056 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
1057 if (baseType && !baseType.isGround())
1058 return WalkResult::advance();
1060 !isOverdefined(fieldRef)) {
1065 return WalkResult::advance();
1070 if (op->getNumResults() != 1 && !isa<InstanceOp>(op))
1071 return WalkResult::advance();
1074 if (dropIfDead(op,
"Trivially dead"))
1075 return WalkResult::advance();
1079 if (op->hasTrait<mlir::OpTrait::ConstantLike>())
1080 return WalkResult::advance();
1083 builder.setInsertionPoint(op);
1084 bool foldedAny =
false;
1085 for (
auto result : op->getResults())
1086 foldedAny |= replaceValueIfPossible(result);
1092 if (foldedAny && dropIfDead(op,
"Made dead"))
1093 return WalkResult::advance();
1095 return WalkResult::advance();
1100 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.
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.
Location getLoc() const
Get the location associated with the value of this field ref.
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
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,...
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.
llvm::raw_ostream & operator<<(llvm::raw_ostream &os, const InstanceInfo::LatticeValue &value)
::mlir::Type getFinalTypeByFieldID(Type type, uint64_t fieldID)
uint64_t getMaxFieldID(Type)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
APSInt extOrTruncZeroWidth(APSInt value, unsigned width)
A safe version of APSInt::extOrTrunc that will NOT assert on zero-width signed APSInts.
bool operator==(uint64_t a, const FVInt &b)
bool operator!=(uint64_t a, const FVInt &b)
def reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)