12#include "llvm/ADT/DenseSet.h"
21#define GEN_PASS_DEF_LOWERSYMBOLICVALUESPASS
22#include "circt/Dialect/Verif/Passes.h.inc"
27struct LowerSymbolicValuesPass
28 : verif::impl::LowerSymbolicValuesPassBase<LowerSymbolicValuesPass> {
29 using LowerSymbolicValuesPassBase::LowerSymbolicValuesPassBase;
30 void runOnOperation()
override;
31 LogicalResult lowerToExtModule();
32 void lowerToAnySeqWire();
33 LogicalResult lowerToHWInputs();
37void LowerSymbolicValuesPass::runOnOperation() {
39 case SymbolicValueLowering::ExtModule:
40 if (failed(lowerToExtModule()))
43 case SymbolicValueLowering::Yosys:
46 case SymbolicValueLowering::HWInput:
47 if (failed(lowerToHWInputs()))
56LogicalResult LowerSymbolicValuesPass::lowerToExtModule() {
57 auto &symbolTable = getAnalysis<SymbolTable>();
58 DenseMap<Type, HWModuleExternOp> extmoduleOps;
59 auto result = getOperation().walk([&](SymbolicValueOp op) -> WalkResult {
61 auto numBits = hw::getBitWidth(op.getType());
63 return op.emitError() <<
"symbolic value bit width unknown";
67 auto builder = OpBuilder::atBlockEnd(getOperation().getBody());
68 auto flatType = builder.getIntegerType(numBits);
69 auto &extmoduleOp = extmoduleOps[flatType];
71 extmoduleOp = HWModuleExternOp::create(
73 builder.getStringAttr(Twine(
"circt.symbolic_value.") +
76 "circt_symbolic_value",
77 builder.getArrayAttr(ParamDeclAttr::get(
78 builder.getContext(), builder.getStringAttr(
"WIDTH"),
79 builder.getI32Type(), Attribute())));
80 symbolTable.insert(extmoduleOp);
85 builder.setInsertionPoint(op);
86 auto instOp = InstanceOp::create(
87 builder, op.getLoc(), extmoduleOp,
88 builder.getStringAttr(
"symbolic_value"), ArrayRef<Value>{},
89 builder.getArrayAttr(ParamDeclAttr::get(
90 builder.getContext(), builder.getStringAttr(
"WIDTH"),
91 builder.getI32Type(), builder.getI32IntegerAttr(numBits))));
92 Value value = instOp.getResult(0);
95 if (op.getType() != value.getType())
99 op.replaceAllUsesWith(value);
103 return failure(result.wasInterrupted());
107void LowerSymbolicValuesPass::lowerToAnySeqWire() {
108 getOperation().walk([&](SymbolicValueOp op) {
111 OpBuilder builder(op);
113 sv::addSVAttributes(wireOp,
114 sv::SVAttributeAttr::get(&getContext(),
"anyseq"));
118 op.replaceAllUsesWith(value);
124LogicalResult LowerSymbolicValuesPass::lowerToHWInputs() {
125 auto module = getOperation();
126 DenseSet<StringAttr> referencedModules;
127 module.walk([&](InstanceOp op) {
128 referencedModules.insert(op.getReferencedModuleNameAttr());
131 auto result =
module.walk([&](SymbolicValueOp op) -> WalkResult {
132 if (!op->getParentOfType<HWModuleOp>())
133 return op.emitError()
134 << "cannot lower symbolic value to hw.module input outside of an "
136 return WalkResult::advance();
138 if (result.wasInterrupted())
141 for (
auto hwModule : module.getOps<
HWModuleOp>()) {
142 SmallVector<SymbolicValueOp> symbolicValues;
143 hwModule.walk([&](SymbolicValueOp op) { symbolicValues.push_back(op); });
144 if (symbolicValues.empty())
147 if (referencedModules.contains(hwModule.getModuleNameAttr())) {
149 <<
"cannot lower symbolic values in instantiated module '"
150 << hwModule.getModuleName()
151 <<
"' to HW inputs; run the 'hw-input' lowering strategy after "
152 "flattening modules";
156 for (
auto symbolicValue : symbolicValues) {
157 auto [name, arg] = hwModule.insertInput(
158 hwModule.getNumInputPorts(),
159 StringAttr::get(module.getContext(),
"symbolic_value"),
160 symbolicValue.getType());
162 symbolicValue.getResult().replaceAllUsesWith(arg);
163 symbolicValue.erase();
create(data_type, name=None, sym_name=None)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
This holds the name, type, direction of a module's ports.