25 #include "mlir/IR/ImplicitLocOpBuilder.h"
26 #include "llvm/ADT/APSInt.h"
27 #include "llvm/ADT/TypeSwitch.h"
28 #include "llvm/Support/Debug.h"
30 #define DEBUG_TYPE "firrtl-remove-resets"
32 using namespace circt;
33 using namespace firrtl;
36 void runOnOperation()
override;
42 "---------------------------------------------------===\n"
43 <<
"Module: '" << getOperation().
getName() <<
"'\n";);
45 bool madeModifications =
false;
46 SmallVector<InvalidValueOp> invalidOps;
47 for (
auto &op : llvm::make_early_inc_range(getOperation().getOps())) {
49 if (
auto inv = dyn_cast<InvalidValueOp>(op)) {
50 invalidOps.push_back(inv);
53 auto reg = dyn_cast<RegResetOp>(op);
61 return src.isa<InvalidValueOp>();
64 RegOp newReg =
builder.create<RegOp>(
65 reg.getResult().getType(),
reg.getClockVal(),
reg.getNameAttr(),
66 reg.getNameKindAttr(),
reg.getAnnotationsAttr(),
67 reg.getInnerSymAttr(),
reg.getForceableAttr());
68 reg.replaceAllUsesWith(newReg);
70 madeModifications =
true;
77 if (!isa<AsyncResetType>(
reg.getResetSignal().getType()))
80 reg.getResetValue(),
true,
true,
true,
82 if (src.isa<ConstantOp, InvalidValueOp, SpecialConstantOp,
83 AggregateConstantOp>())
85 auto diag = emitError(reg.getLoc());
86 auto [fieldName, rootKnown] = getFieldName(dst);
87 diag <<
"register " << reg.getNameAttr()
88 <<
" has an async reset, but its reset value";
90 diag <<
" \"" << fieldName <<
"\"";
91 diag <<
" is not driven with a constant value through wires, "
93 std::tie(fieldName, rootKnown) = getFieldName(src);
94 diag.attachNote(src.getLoc())
96 << (rootKnown ? (
"\"" + fieldName +
"\"") :
"here");
100 return signalPassFailure();
104 for (
auto inv : invalidOps) {
106 if (inv->getUses().empty()) {
108 madeModifications =
true;
111 ImplicitLocOpBuilder
builder(inv.getLoc(), inv);
114 .
Case<ClockType, AsyncResetType, ResetType>(
115 [&](
auto type) -> Value {
116 return builder.create<SpecialConstantOp>(
117 type,
builder.getBoolAttr(
false));
119 .Case<IntType>([&](
IntType type) -> Value {
122 .Case<BundleType, FVectorType>([&](
auto type) -> Value {
126 return builder.create<BitCastOp>(type, zero);
129 llvm_unreachable(
"all types are supported");
132 inv.replaceAllUsesWith(replacement);
134 madeModifications =
true;
137 if (!madeModifications)
138 return markAllAnalysesPreserved();
142 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.
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.
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.
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
mlir::raw_indented_ostream & dbgs()
def reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None)
void runOnOperation() override