25 #include "mlir/IR/ImplicitLocOpBuilder.h"
26 #include "mlir/Pass/Pass.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"
35 #define GEN_PASS_DEF_SFCCOMPAT
36 #include "circt/Dialect/FIRRTL/Passes.h.inc"
40 using namespace circt;
41 using namespace firrtl;
45 void runOnOperation()
override;
50 llvm::dbgs() <<
"==----- Running SFCCompat "
51 "---------------------------------------------------===\n"
52 <<
"Module: '" << getOperation().
getName() <<
"'\n";);
54 bool madeModifications =
false;
55 SmallVector<InvalidValueOp> invalidOps;
57 auto fullAsyncResetAttr =
59 auto isFullAsyncResetAnno = [fullAsyncResetAttr](
Annotation anno) {
60 return anno.getClassAttr() == fullAsyncResetAttr;
63 getOperation(), [&](
unsigned argNum,
Annotation anno) {
64 return isFullAsyncResetAnno(anno);
67 [isFullAsyncResetAnno, &fullAsyncResetExists](Operation *op) {
68 fullAsyncResetExists |=
71 madeModifications |= fullAsyncResetExists;
73 auto result = getOperation()->walk([&](Operation *op) {
75 if (
auto inv = dyn_cast<InvalidValueOp>(op)) {
76 invalidOps.push_back(inv);
77 return WalkResult::advance();
79 auto reg = dyn_cast<RegResetOp>(op);
81 return WalkResult::advance();
85 if (!fullAsyncResetExists &&
88 return src.isa<InvalidValueOp>();
90 ImplicitLocOpBuilder builder(
reg.getLoc(),
reg);
91 RegOp newReg = builder.create<RegOp>(
92 reg.getResult().getType(),
reg.getClockVal(),
reg.getNameAttr(),
93 reg.getNameKindAttr(),
reg.getAnnotationsAttr(),
94 reg.getInnerSymAttr(),
reg.getForceableAttr());
95 reg.replaceAllUsesWith(newReg);
97 madeModifications =
true;
98 return WalkResult::advance();
104 if (!isa<AsyncResetType>(
reg.getResetSignal().getType()))
105 return WalkResult::advance();
107 reg.getResetValue(),
true,
true,
true,
109 if (src.isa<ConstantOp, InvalidValueOp, SpecialConstantOp,
110 AggregateConstantOp>())
112 auto diag = emitError(reg.getLoc());
113 auto [fieldName, rootKnown] = getFieldName(dst);
114 diag <<
"register " << reg.getNameAttr()
115 <<
" has an async reset, but its reset value";
117 diag <<
" \"" << fieldName <<
"\"";
118 diag <<
" is not driven with a constant value through wires, "
119 "nodes, or connects";
120 std::tie(fieldName, rootKnown) = getFieldName(src);
121 diag.attachNote(src.getLoc())
122 <<
"reset driver is "
123 << (rootKnown ? (
"\"" + fieldName +
"\"") :
"here");
126 return WalkResult::advance();
127 return WalkResult::interrupt();
130 if (result.wasInterrupted())
131 return signalPassFailure();
134 for (
auto inv : invalidOps) {
136 if (inv->getUses().empty()) {
138 madeModifications =
true;
141 ImplicitLocOpBuilder builder(inv.getLoc(), inv);
144 .
Case<ClockType, AsyncResetType, ResetType>(
145 [&](
auto type) -> Value {
146 return builder.create<SpecialConstantOp>(
147 type, builder.getBoolAttr(
false));
149 .Case<IntType>([&](
IntType type) -> Value {
152 .Case<BundleType, FVectorType>([&](
auto type) -> Value {
155 auto zero = builder.create<ConstantOp>(APSInt(*
width));
156 return builder.create<BitCastOp>(type, zero);
159 llvm_unreachable(
"all types are supported");
162 inv.replaceAllUsesWith(replacement);
164 madeModifications =
true;
167 if (!madeModifications)
168 return markAllAnalysesPreserved();
172 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.
bool removeAnnotations(llvm::function_ref< bool(Annotation)> predicate)
Remove all annotations from this annotation set for which predicate returns true.
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.
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.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
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