22 #include "mlir/IR/Iterators.h"
23 #include "mlir/IR/Threading.h"
24 #include "mlir/Pass/Pass.h"
25 #include "llvm/ADT/APSInt.h"
26 #include "llvm/ADT/TinyPtrVector.h"
27 #include "llvm/Support/Debug.h"
28 #include "llvm/Support/ScopedPrinter.h"
32 #define GEN_PASS_DEF_IMCONSTPROP
33 #include "circt/Dialect/FIRRTL/Passes.h.inc"
37 using namespace circt;
38 using namespace firrtl;
40 #define DEBUG_TYPE "IMCP"
44 return isa<WireOp, RegResetOp, RegOp>(op);
49 return isa<SubindexOp, SubaccessOp, SubfieldOp, OpenSubfieldOp,
50 OpenSubindexOp, RefSubOp>(op);
56 return isa<NodeOp, RefResolveOp, RefSendOp>(op);
65 if (type_isa<RefType>(op->getResult(0).getType()))
99 LatticeValue() : valueAndTag(nullptr, Kind::Unknown) {}
101 LatticeValue(IntegerAttr attr)
102 : valueAndTag(attr, Kind::Constant) {}
103 LatticeValue(StringAttr attr)
104 : valueAndTag(attr, Kind::Constant) {}
106 static LatticeValue getOverdefined() {
108 result.markOverdefined();
112 bool isUnknown()
const {
return valueAndTag.getInt() == Kind::Unknown; }
113 bool isConstant()
const {
return valueAndTag.getInt() == Kind::Constant; }
114 bool isOverdefined()
const {
115 return valueAndTag.getInt() == Kind::Overdefined;
119 void markOverdefined() {
120 valueAndTag.setPointerAndInt(
nullptr, Kind::Overdefined);
124 void markConstant(IntegerAttr value) {
125 valueAndTag.setPointerAndInt(value, Kind::Constant);
130 Attribute getValue()
const {
return valueAndTag.getPointer(); }
140 bool mergeIn(LatticeValue rhs) {
142 if (isOverdefined() || rhs.isUnknown())
147 valueAndTag = rhs.valueAndTag;
154 if (valueAndTag != rhs.valueAndTag) {
161 bool operator==(
const LatticeValue &other)
const {
162 return valueAndTag == other.valueAndTag;
164 bool operator!=(
const LatticeValue &other)
const {
165 return valueAndTag != other.valueAndTag;
171 llvm::PointerIntPair<Attribute, 2, Kind> valueAndTag;
177 const LatticeValue &lattice) {
178 if (lattice.isUnknown())
179 return os <<
"<Unknown>";
180 if (lattice.isOverdefined())
181 return os <<
"<Overdefined>";
182 return os <<
"<" << lattice.getConstant() <<
">";
186 struct IMConstPropPass
187 :
public circt::firrtl::impl::IMConstPropBase<IMConstPropPass> {
189 void runOnOperation()
override;
190 void rewriteModuleBody(FModuleOp module);
193 bool isBlockExecutable(Block *block)
const {
194 return executableBlocks.count(block);
197 bool isOverdefined(
FieldRef value)
const {
198 auto it = latticeValues.find(value);
199 return it != latticeValues.end() && it->second.isOverdefined();
204 void markOverdefined(Value value) {
205 FieldRef fieldRef = getOrCacheFieldRefFromValue(value);
206 auto firrtlType = type_dyn_cast<FIRRTLType>(value.getType());
207 if (!firrtlType || type_isa<PropertyType>(firrtlType)) {
208 markOverdefined(fieldRef);
219 void markOverdefined(
FieldRef value) {
220 auto &entry = latticeValues[value];
221 if (!entry.isOverdefined()) {
224 <<
"Setting overdefined : (" <<
getFieldName(value).first <<
")\n";
226 entry.markOverdefined();
227 changedLatticeValueWorklist.push_back(value);
234 void mergeLatticeValue(
FieldRef value, LatticeValue &valueEntry,
235 LatticeValue source) {
236 if (valueEntry.mergeIn(source)) {
239 <<
"Changed to " << valueEntry <<
" : (" << value <<
")\n";
241 changedLatticeValueWorklist.push_back(value);
245 void mergeLatticeValue(
FieldRef value, LatticeValue source) {
247 if (source.isUnknown())
249 mergeLatticeValue(value, latticeValues[value], source);
255 auto it = latticeValues.find(from);
256 if (it == latticeValues.end())
258 mergeLatticeValue(result, it->second);
261 void mergeLatticeValue(Value result, Value from) {
262 FieldRef fieldRefFrom = getOrCacheFieldRefFromValue(from);
263 FieldRef fieldRefResult = getOrCacheFieldRefFromValue(result);
264 if (!type_isa<FIRRTLType>(result.getType()))
265 return mergeLatticeValue(fieldRefResult, fieldRefFrom);
267 if (type_isa<PropertyType>(result.getType()))
268 return mergeLatticeValue(fieldRefResult, fieldRefFrom);
270 [&](uint64_t fieldID,
auto,
auto) {
271 mergeLatticeValue(fieldRefResult.getSubField(fieldID),
272 fieldRefFrom.getSubField(fieldID));
281 void setLatticeValue(
FieldRef value, LatticeValue source) {
283 if (source.isUnknown())
287 auto &valueEntry = latticeValues[value];
288 if (valueEntry != source) {
289 changedLatticeValueWorklist.push_back(value);
297 FieldRef getOrCacheFieldRefFromValue(Value value) {
298 if (!value.getDefiningOp() || !
isAggregate(value.getDefiningOp()))
300 auto &fieldRef = valueToFieldRef[value];
310 bool allowTruncation =
false);
313 void markBlockExecutable(Block *block);
314 void markWireOp(WireOp wireOrReg);
315 void markMemOp(MemOp mem);
317 void markInvalidValueOp(InvalidValueOp invalid);
318 void markAggregateConstantOp(AggregateConstantOp constant);
319 void markInstanceOp(InstanceOp instance);
320 void markObjectOp(ObjectOp
object);
321 template <
typename OpTy>
322 void markConstantValueOp(OpTy op);
325 void visitRefSend(RefSendOp send,
FieldRef changedFieldRef);
326 void visitRefResolve(RefResolveOp resolve,
FieldRef changedFieldRef);
327 void mergeOnlyChangedLatticeValue(Value dest, Value src,
329 void visitNode(NodeOp node,
FieldRef changedFieldRef);
330 void visitOperation(Operation *op,
FieldRef changedFieldRef);
337 DenseMap<FieldRef, LatticeValue> latticeValues;
340 SmallPtrSet<Block *, 16> executableBlocks;
344 SmallVector<FieldRef, 64> changedLatticeValueWorklist;
347 DenseMap<FieldRef, llvm::TinyPtrVector<Operation *>> fieldRefToUsers;
351 llvm::DenseMap<Value, FieldRef> valueToFieldRef;
355 DenseMap<BlockArgument, llvm::TinyPtrVector<Value>>
356 resultPortToInstanceResultMapping;
360 llvm::ScopedPrinter logger{llvm::dbgs()};
366 void IMConstPropPass::runOnOperation() {
367 auto circuit = getOperation();
369 { logger.startLine() <<
"IMConstProp : " << circuit.getName() <<
"\n"; });
371 instanceGraph = &getAnalysis<InstanceGraph>();
374 for (
auto module : circuit.getBodyBlock()->getOps<FModuleOp>()) {
375 if (module.isPublic()) {
376 markBlockExecutable(module.getBodyBlock());
377 for (
auto port : module.getBodyBlock()->getArguments())
378 markOverdefined(port);
383 while (!changedLatticeValueWorklist.empty()) {
384 FieldRef changedFieldRef = changedLatticeValueWorklist.pop_back_val();
385 for (Operation *user : fieldRefToUsers[changedFieldRef]) {
386 if (isBlockExecutable(user->getBlock()))
387 visitOperation(user, changedFieldRef);
392 mlir::parallelForEach(circuit.getContext(),
393 circuit.getBodyBlock()->getOps<FModuleOp>(),
394 [&](
auto op) { rewriteModuleBody(op); });
397 instanceGraph =
nullptr;
398 latticeValues.clear();
399 executableBlocks.clear();
400 assert(changedLatticeValueWorklist.empty());
401 fieldRefToUsers.clear();
402 valueToFieldRef.clear();
403 resultPortToInstanceResultMapping.clear();
409 LatticeValue IMConstPropPass::getExtendedLatticeValue(
FieldRef value,
411 bool allowTruncation) {
413 auto it = latticeValues.find(value);
414 if (it == latticeValues.end())
415 return LatticeValue();
417 auto result = it->second;
419 if (result.isUnknown() || result.isOverdefined())
423 if (isa<PropertyType>(destType))
426 auto constant = result.getConstant();
429 auto intAttr = dyn_cast<IntegerAttr>(constant);
430 assert(intAttr &&
"unsupported lattice attribute kind");
435 if (
auto boolAttr = dyn_cast<BoolAttr>(intAttr))
441 return LatticeValue::getOverdefined();
444 auto resultConstant = intAttr.getAPSInt();
445 auto destWidth = baseType.getBitWidthOrSentinel();
447 return LatticeValue::getOverdefined();
448 if (resultConstant.getBitWidth() == (
unsigned)destWidth)
453 return LatticeValue(
IntegerAttr::get(destType.getContext(), resultConstant));
460 void IMConstPropPass::markBlockExecutable(Block *block) {
461 if (!executableBlocks.insert(block).second)
466 for (
auto ba : block->getArguments())
470 for (
auto &op : *block) {
472 TypeSwitch<Operation *>(&op)
473 .Case<RegOp, RegResetOp>(
474 [&](
auto reg) { markOverdefined(op.getResult(0)); })
475 .Case<WireOp>([&](
auto wire) { markWireOp(wire); })
476 .Case<ConstantOp, SpecialConstantOp, StringConstantOp,
477 FIntegerConstantOp, BoolConstantOp>(
478 [&](
auto constOp) { markConstantValueOp(constOp); })
479 .Case<AggregateConstantOp>(
480 [&](
auto aggConstOp) { markAggregateConstantOp(aggConstOp); })
481 .Case<InvalidValueOp>(
482 [&](
auto invalid) { markInvalidValueOp(invalid); })
483 .Case<InstanceOp>([&](
auto instance) { markInstanceOp(instance); })
484 .Case<ObjectOp>([&](
auto obj) { markObjectOp(obj); })
485 .Case<MemOp>([&](
auto mem) { markMemOp(mem); })
487 [&](
auto layer) { markBlockExecutable(layer.getBody(0)); })
488 .Default([&](
auto _) {
489 if (isa<mlir::UnrealizedConversionCastOp, VerbatimExprOp,
490 VerbatimWireOp, SubaccessOp>(op) ||
491 op.getNumOperands() == 0) {
495 for (
auto result : op.getResults())
496 markOverdefined(result);
508 bool hasAggregateOperand =
509 llvm::any_of(op.getOperandTypes(), [](Type type) {
510 return type_isa<FVectorType, BundleType>(type);
513 for (
auto result : op.getResults())
514 if (hasAggregateOperand ||
515 type_isa<FVectorType, BundleType>(result.getType()))
516 markOverdefined(result);
523 for (
auto operand : op.getOperands()) {
524 auto fieldRef = getOrCacheFieldRefFromValue(operand);
525 auto firrtlType = type_dyn_cast<FIRRTLType>(operand.getType());
529 if (type_isa<PropertyType>(firrtlType)) {
530 fieldRefToUsers[fieldRef].push_back(&op);
534 fieldRefToUsers[fieldRef.
getSubField(fieldID)].push_back(&op);
542 void IMConstPropPass::markWireOp(WireOp wire) {
543 auto type = type_dyn_cast<FIRRTLType>(wire.getResult().getType());
544 if (!type ||
hasDontTouch(wire.getResult()) || wire.isForceable()) {
545 for (
auto result : wire.getResults())
546 markOverdefined(result);
553 void IMConstPropPass::markMemOp(MemOp mem) {
554 for (
auto result : mem.getResults())
555 markOverdefined(result);
558 template <
typename OpTy>
559 void IMConstPropPass::markConstantValueOp(OpTy op) {
560 mergeLatticeValue(getOrCacheFieldRefFromValue(op),
561 LatticeValue(op.getValueAttr()));
564 void IMConstPropPass::markAggregateConstantOp(AggregateConstantOp constant) {
565 walkGroundTypes(constant.getType(), [&](uint64_t fieldID,
auto,
auto) {
566 mergeLatticeValue(FieldRef(constant, fieldID),
567 LatticeValue(cast<IntegerAttr>(
568 constant.getAttributeFromFieldID(fieldID))));
572 void IMConstPropPass::markInvalidValueOp(InvalidValueOp invalid) {
573 markOverdefined(invalid.getResult());
578 void IMConstPropPass::markInstanceOp(InstanceOp instance) {
580 Operation *op = instance.getReferencedModule(*instanceGraph);
584 if (!isa<FModuleOp>(op)) {
585 auto module = dyn_cast<FModuleLike>(op);
586 for (
size_t resultNo = 0, e = instance.getNumResults(); resultNo != e;
588 auto portVal = instance.getResult(resultNo);
594 markOverdefined(portVal);
600 auto fModule = cast<FModuleOp>(op);
601 markBlockExecutable(fModule.getBodyBlock());
605 for (
size_t resultNo = 0, e = instance.getNumResults(); resultNo != e;
607 auto instancePortVal = instance.getResult(resultNo);
615 BlockArgument modulePortVal = fModule.getArgument(resultNo);
617 resultPortToInstanceResultMapping[modulePortVal].push_back(instancePortVal);
621 mergeLatticeValue(instancePortVal, modulePortVal);
625 void IMConstPropPass::markObjectOp(ObjectOp obj) {
627 markOverdefined(obj);
630 static std::optional<uint64_t>
633 assert(!type_isa<RefType>(connectionType));
644 void IMConstPropPass::mergeOnlyChangedLatticeValue(Value dest, Value src,
648 auto destType = dest.getType();
649 if (
auto refType = type_dyn_cast<RefType>(destType))
650 destType = refType.getType();
652 if (!isa<FIRRTLType>(destType)) {
655 markOverdefined(src);
656 return markOverdefined(dest);
659 auto fieldRefSrc = getOrCacheFieldRefFromValue(src);
660 auto fieldRefDest = getOrCacheFieldRefFromValue(dest);
664 if (
auto srcOffset =
getFieldIDOffset(changedFieldRef, destType, fieldRefSrc))
665 mergeLatticeValue(fieldRefDest.getSubField(*srcOffset),
666 fieldRefSrc.getSubField(*srcOffset));
670 if (
auto destOffset =
672 mergeLatticeValue(fieldRefDest.getSubField(*destOffset),
673 fieldRefSrc.getSubField(*destOffset));
676 void IMConstPropPass::visitConnectLike(FConnectLike
connect,
679 auto destType =
connect.getDest().getType();
680 if (
auto refType = type_dyn_cast<RefType>(destType))
681 destType = refType.getType();
684 if (!isa<FIRRTLType>(destType)) {
685 markOverdefined(
connect.getSrc());
686 return markOverdefined(
connect.getDest());
689 auto fieldRefSrc = getOrCacheFieldRefFromValue(
connect.getSrc());
690 auto fieldRefDest = getOrCacheFieldRefFromValue(
connect.getDest());
691 if (
auto subaccess = fieldRefDest.getValue().getDefiningOp<SubaccessOp>()) {
695 Value parent = subaccess.getInput();
696 while (parent.getDefiningOp() &&
697 parent.getDefiningOp()->getNumOperands() > 0)
698 parent = parent.getDefiningOp()->getOperand(0);
699 return markOverdefined(parent);
702 auto propagateElementLattice = [&](uint64_t fieldID,
FIRRTLType destType) {
703 auto fieldRefDestConnected = fieldRefDest.getSubField(fieldID);
704 assert(!firrtl::type_isa<FIRRTLBaseType>(destType) ||
705 firrtl::type_cast<FIRRTLBaseType>(destType).isGround());
709 getExtendedLatticeValue(fieldRefSrc.getSubField(fieldID), destType);
710 if (srcValue.isUnknown())
715 if (
auto blockArg = dyn_cast<BlockArgument>(fieldRefDest.getValue())) {
716 for (
auto userOfResultPort : resultPortToInstanceResultMapping[blockArg])
718 FieldRef(userOfResultPort, fieldRefDestConnected.getFieldID()),
721 return mergeLatticeValue(fieldRefDestConnected, srcValue);
724 auto dest = cast<mlir::OpResult>(fieldRefDest.getValue());
729 return mergeLatticeValue(fieldRefDestConnected, srcValue);
733 if (
auto instance = dest.getDefiningOp<InstanceOp>()) {
735 mergeLatticeValue(fieldRefDestConnected, srcValue);
736 auto mod = instance.getReferencedModule<FModuleOp>(*instanceGraph);
740 BlockArgument modulePortVal = mod.getArgument(dest.getResultNumber());
742 return mergeLatticeValue(
743 FieldRef(modulePortVal, fieldRefDestConnected.getFieldID()),
749 if (dest.getDefiningOp<MemOp>())
753 if (isa_and_nonnull<ObjectSubfieldOp>(dest.getDefiningOp()))
756 connect.emitError(
"connectlike operation unhandled by IMConstProp")
757 .attachNote(
connect.getDest().getLoc())
758 <<
"connect destination is here";
761 if (
auto srcOffset =
getFieldIDOffset(changedFieldRef, destType, fieldRefSrc))
762 propagateElementLattice(
764 firrtl::type_cast<FIRRTLType>(
767 if (
auto relativeDest =
769 propagateElementLattice(
771 firrtl::type_cast<FIRRTLType>(
775 void IMConstPropPass::visitRefSend(RefSendOp send,
FieldRef changedFieldRef) {
777 return mergeOnlyChangedLatticeValue(send.getResult(), send.getBase(),
781 void IMConstPropPass::visitRefResolve(RefResolveOp resolve,
785 return mergeOnlyChangedLatticeValue(resolve.getResult(), resolve.getRef(),
789 void IMConstPropPass::visitNode(NodeOp node,
FieldRef changedFieldRef) {
790 if (
hasDontTouch(node.getResult()) || node.isForceable()) {
791 for (
auto result : node.getResults())
792 markOverdefined(result);
796 return mergeOnlyChangedLatticeValue(node.getResult(), node.getInput(),
806 void IMConstPropPass::visitOperation(Operation *op,
FieldRef changedField) {
808 if (
auto connectLikeOp = dyn_cast<FConnectLike>(op))
809 return visitConnectLike(connectLikeOp, changedField);
810 if (
auto sendOp = dyn_cast<RefSendOp>(op))
811 return visitRefSend(sendOp, changedField);
812 if (
auto resolveOp = dyn_cast<RefResolveOp>(op))
813 return visitRefResolve(resolveOp, changedField);
814 if (
auto nodeOp = dyn_cast<NodeOp>(op))
815 return visitNode(nodeOp, changedField);
826 auto isOverdefinedFn = [&](Value value) {
827 return isOverdefined(getOrCacheFieldRefFromValue(value));
829 if (llvm::all_of(op->getResults(), isOverdefinedFn))
834 if (op->getNumOperands() > 128) {
835 for (
auto value : op->getResults())
836 markOverdefined(value);
842 SmallVector<Attribute, 8> operandConstants;
843 operandConstants.reserve(op->getNumOperands());
844 bool hasUnknown =
false;
845 for (Value operand : op->getOperands()) {
847 auto &operandLattice = latticeValues[getOrCacheFieldRefFromValue(operand)];
852 if (operandLattice.isUnknown())
857 if (operandLattice.isConstant())
858 operandConstants.push_back(operandLattice.getValue());
860 operandConstants.push_back({});
865 SmallVector<OpFoldResult, 8> foldResults;
866 foldResults.reserve(op->getNumResults());
867 if (failed(op->fold(operandConstants, foldResults))) {
869 logger.startLine() <<
"Folding Failed operation : '" << op->getName()
875 for (
auto value : op->getResults())
876 markOverdefined(value);
881 logger.getOStream() <<
"\n";
882 logger.startLine() <<
"Folding operation : '" << op->getName() <<
"\n";
884 logger.getOStream() <<
"( ";
885 for (
auto cst : operandConstants)
887 logger.getOStream() <<
"{} ";
889 logger.getOStream() << cst <<
" ";
891 logger.getOStream() <<
") -> { ";
893 for (
auto &r : foldResults) {
894 logger.getOStream() << r <<
" ";
897 logger.getOStream() <<
"}\n";
904 if (foldResults.empty())
905 return visitOperation(op, changedField);
908 assert(foldResults.size() == op->getNumResults() &&
"invalid result size");
909 for (
unsigned i = 0, e = foldResults.size(); i != e; ++i) {
911 LatticeValue resultLattice;
912 OpFoldResult foldResult = foldResults[i];
913 if (Attribute foldAttr = dyn_cast<Attribute>(foldResult)) {
914 if (
auto intAttr = dyn_cast<IntegerAttr>(foldAttr))
915 resultLattice = LatticeValue(intAttr);
916 else if (
auto strAttr = dyn_cast<StringAttr>(foldAttr))
917 resultLattice = LatticeValue(strAttr);
919 resultLattice = LatticeValue::getOverdefined();
922 latticeValues[getOrCacheFieldRefFromValue(foldResult.get<Value>())];
925 mergeLatticeValue(getOrCacheFieldRefFromValue(op->getResult(i)),
930 void IMConstPropPass::rewriteModuleBody(FModuleOp module) {
931 auto *body = module.getBodyBlock();
933 if (!executableBlocks.count(body))
936 auto builder = OpBuilder::atBlockBegin(body);
940 auto cursor = builder.create<firrtl::ConstantOp>(module.getLoc(), APSInt(1));
941 builder.setInsertionPoint(cursor);
944 DenseMap<std::pair<Attribute, Type>, Operation *> constPool;
946 std::function<Value(Attribute, Type, Location)> getConst =
947 [&](Attribute constantValue, Type type, Location loc) -> Value {
948 auto constIt = constPool.find({constantValue, type});
949 if (constIt != constPool.end()) {
950 auto *cst = constIt->second;
952 cst->setLoc(builder.getFusedLoc({cst->getLoc(), loc}));
953 return cst->getResult(0);
955 OpBuilder::InsertionGuard x(builder);
956 builder.setInsertionPoint(cursor);
961 if (
auto refType = type_dyn_cast<RefType>(type)) {
962 assert(!type_cast<RefType>(type).getForceable() &&
963 "Attempting to materialize rwprobe of constant, shouldn't happen");
964 auto inner = getConst(constantValue, refType.getType(), loc);
966 cst = builder.create<RefSendOp>(loc, inner);
968 cst = module->getDialect()->materializeConstant(builder, constantValue,
970 assert(cst &&
"all FIRRTL constants can be materialized");
971 constPool.insert({{constantValue, type}, cst});
972 return cst->getResult(0);
977 auto replaceValueIfPossible = [&](Value value) ->
bool {
981 auto replaceIfNotConnect = [&value](Value replacement) {
982 value.replaceUsesWithIf(replacement, [](OpOperand &operand) {
983 return !isa<FConnectLike>(operand.getOwner()) ||
984 operand.getOperandNumber() != 0;
990 if (it == latticeValues.end() || it->second.isOverdefined() ||
991 it->second.isUnknown())
997 if (!type_isa<FIRRTLBaseType, RefType, FIntegerType, StringType, BoolType>(
1002 getConst(it->second.getValue(), value.getType(), value.
getLoc());
1004 replaceIfNotConnect(cstValue);
1009 for (
auto &port : body->getArguments())
1010 replaceValueIfPossible(port);
1018 bool aboveCursor =
false;
1019 module.walk<mlir::WalkOrder::PostOrder, mlir::ReverseIterator>(
1020 [&](Operation *op) {
1021 auto dropIfDead = [&](Operation *op,
const Twine &debugPrefix) {
1022 if (op->use_empty() &&
1025 { logger.getOStream() << debugPrefix <<
" : " << op <<
"\n"; });
1035 dropIfDead(op,
"Trivially dead materialized constant");
1036 return WalkResult::advance();
1042 return WalkResult::advance();
1046 if (
auto connect = dyn_cast<FConnectLike>(op)) {
1047 if (
auto *destOp =
connect.getDest().getDefiningOp()) {
1048 auto fieldRef = getOrCacheFieldRefFromValue(
connect.getDest());
1054 auto type = type_dyn_cast<FIRRTLType>(
connect.getDest().getType());
1056 return WalkResult::advance();
1057 auto baseType = type_dyn_cast<FIRRTLBaseType>(type);
1058 if (baseType && !baseType.isGround())
1059 return WalkResult::advance();
1061 !isOverdefined(fieldRef)) {
1066 return WalkResult::advance();
1071 if (op->getNumResults() != 1 && !isa<InstanceOp>(op))
1072 return WalkResult::advance();
1075 if (dropIfDead(op,
"Trivially dead"))
1076 return WalkResult::advance();
1080 if (op->hasTrait<mlir::OpTrait::ConstantLike>())
1081 return WalkResult::advance();
1084 builder.setInsertionPoint(op);
1085 bool foldedAny =
false;
1086 for (
auto result : op->getResults())
1087 foldedAny |= replaceValueIfPossible(result);
1093 if (foldedAny && dropIfDead(op,
"Made dead"))
1094 return WalkResult::advance();
1096 return WalkResult::advance();
1101 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...
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,...
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)