26 #include "mlir/IR/ImplicitLocOpBuilder.h"
27 #include "llvm/ADT/APSInt.h"
28 #include "llvm/ADT/TypeSwitch.h"
29 #include "llvm/Support/Debug.h"
31 #define DEBUG_TYPE "firrtl-remove-resets"
33 using namespace circt;
34 using namespace firrtl;
37 void runOnOperation()
override;
42 llvm::dbgs() <<
"==----- Running SFCCompat "
43 "---------------------------------------------------===\n"
44 <<
"Module: '" << getOperation().
getName() <<
"'\n";);
46 bool madeModifications =
false;
47 SmallVector<InvalidValueOp> invalidOps;
49 bool fullAsyncResetExists =
false;
51 getOperation(), [&](
unsigned argNum,
Annotation anno) {
54 return fullAsyncResetExists =
true;
57 auto result = getOperation()->walk([&](Operation *op) {
59 if (
auto inv = dyn_cast<InvalidValueOp>(op)) {
60 invalidOps.push_back(inv);
61 return WalkResult::advance();
63 auto reg = dyn_cast<RegResetOp>(op);
65 return WalkResult::advance();
69 if (!fullAsyncResetExists &&
72 return src.isa<InvalidValueOp>();
75 RegOp newReg =
builder.create<RegOp>(
76 reg.getResult().getType(),
reg.getClockVal(),
reg.getNameAttr(),
77 reg.getNameKindAttr(),
reg.getAnnotationsAttr(),
78 reg.getInnerSymAttr(),
reg.getForceableAttr());
79 reg.replaceAllUsesWith(newReg);
81 madeModifications =
true;
82 return WalkResult::advance();
88 if (!isa<AsyncResetType>(
reg.getResetSignal().getType()))
89 return WalkResult::advance();
91 reg.getResetValue(),
true,
true,
true,
93 if (src.isa<ConstantOp, InvalidValueOp, SpecialConstantOp,
94 AggregateConstantOp>())
96 auto diag = emitError(reg.getLoc());
97 auto [fieldName, rootKnown] = getFieldName(dst);
98 diag <<
"register " << reg.getNameAttr()
99 <<
" has an async reset, but its reset value";
101 diag <<
" \"" << fieldName <<
"\"";
102 diag <<
" is not driven with a constant value through wires, "
103 "nodes, or connects";
104 std::tie(fieldName, rootKnown) = getFieldName(src);
105 diag.attachNote(src.getLoc())
106 <<
"reset driver is "
107 << (rootKnown ? (
"\"" + fieldName +
"\"") :
"here");
110 return WalkResult::advance();
111 return WalkResult::interrupt();
114 if (result.wasInterrupted())
115 return signalPassFailure();
118 for (
auto inv : invalidOps) {
120 if (inv->getUses().empty()) {
122 madeModifications =
true;
125 ImplicitLocOpBuilder
builder(inv.getLoc(), inv);
128 .
Case<ClockType, AsyncResetType, ResetType>(
129 [&](
auto type) -> Value {
130 return builder.create<SpecialConstantOp>(
131 type,
builder.getBoolAttr(
false));
133 .Case<IntType>([&](
IntType type) -> Value {
136 .Case<BundleType, FVectorType>([&](
auto type) -> Value {
140 return builder.create<BitCastOp>(type, zero);
143 llvm_unreachable(
"all types are supported");
146 inv.replaceAllUsesWith(replacement);
148 madeModifications =
true;
151 if (!madeModifications)
152 return markAllAnalysesPreserved();
156 return std::make_unique<SFCCompatPass>();
assert(baseType &&"element must be base type")
This class represents a reference to a specific field or element of an aggregate value.
static bool removePortAnnotations(Operation *module, llvm::function_ref< bool(unsigned, Annotation)> predicate)
Remove all port annotations from a module or extmodule for which predicate returns true.
This class provides a read-only projection of an annotation.
bool isClass(Args... names) const
Return true if this annotation matches any of the specified class names.
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.
constexpr const char * fullAsyncResetAnnoClass
Annotation that marks a reset (port or wire) and domain.
std::unique_ptr< mlir::Pass > createSFCCompatPass()
bool walkDrivers(FIRRTLBaseValue value, bool lookThroughWires, bool lookThroughNodes, bool lookThroughCasts, WalkDriverCallback callback)
std::optional< int64_t > getBitWidth(FIRRTLBaseType type, bool ignoreFlip=false)
IntegerAttr getIntZerosAttr(Type type)
Utility for generating a constant zero attribute.
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
def reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)
void runOnOperation() override