CIRCT 24.0.0git
Loading...
Searching...
No Matches
LowerSymbolicValues.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
13#include "llvm/ADT/DenseSet.h"
14
15using namespace circt;
16using namespace mlir;
17using namespace verif;
18using namespace hw;
19
20namespace circt {
21namespace verif {
22#define GEN_PASS_DEF_LOWERSYMBOLICVALUESPASS
23#include "circt/Dialect/Verif/Passes.h.inc"
24} // namespace verif
25} // namespace circt
26
27namespace {
28struct LowerSymbolicValuesPass
29 : verif::impl::LowerSymbolicValuesPassBase<LowerSymbolicValuesPass> {
30 using LowerSymbolicValuesPassBase::LowerSymbolicValuesPassBase;
31 void runOnOperation() override;
32 LogicalResult lowerToExtModule();
33 void lowerToAnySeqWire();
34 LogicalResult lowerToHWInputs();
35};
36} // namespace
37
38void LowerSymbolicValuesPass::runOnOperation() {
39 switch (mode) {
40 case SymbolicValueLowering::ExtModule:
41 if (failed(lowerToExtModule()))
42 signalPassFailure();
43 break;
44 case SymbolicValueLowering::Yosys:
45 lowerToAnySeqWire();
46 break;
47 case SymbolicValueLowering::HWInput:
48 if (failed(lowerToHWInputs()))
49 signalPassFailure();
50 break;
51 }
52}
53
54/// Replace all `SymbolicValueOp`s with instances of corresponding extmodules.
55/// This allows tools to treat the modules as blackboxes, or definitions of the
56/// modules may be provided later by the user.
57LogicalResult LowerSymbolicValuesPass::lowerToExtModule() {
58 auto &symbolTable = getAnalysis<SymbolTable>();
59 DenseMap<Type, HWModuleExternOp> extmoduleOps;
60 auto result = getOperation().walk([&](SymbolicValueOp op) -> WalkResult {
61 // Determine the number of bits needed for the symbolic value.
62 auto numBits = hw::getBitWidth(op.getType());
63 if (numBits < 0)
64 return op.emitError() << "symbolic value bit width unknown";
65
66 // If we don't already have an extmodule for this number of bits, create
67 // one.
68 auto builder = OpBuilder::atBlockEnd(getOperation().getBody());
69 auto flatType = builder.getIntegerType(numBits);
70 auto &extmoduleOp = extmoduleOps[flatType];
71 if (!extmoduleOp) {
72 extmoduleOp = HWModuleExternOp::create(
73 builder, op.getLoc(),
74 builder.getStringAttr(Twine("circt.symbolic_value.") +
75 Twine(numBits)),
76 PortInfo{{builder.getStringAttr("z"), flatType, ModulePort::Output}},
77 "circt_symbolic_value",
78 builder.getArrayAttr(ParamDeclAttr::get(
79 builder.getContext(), builder.getStringAttr("WIDTH"),
80 builder.getI32Type(), Attribute())));
81 symbolTable.insert(extmoduleOp);
82 }
83
84 // Instantiate the extmodule as a means of generating a symbolic value with
85 // the correct number of bits.
86 builder.setInsertionPoint(op);
87 auto instOp = InstanceOp::create(
88 builder, op.getLoc(), extmoduleOp,
89 builder.getStringAttr("symbolic_value"), ArrayRef<Value>{},
90 builder.getArrayAttr(ParamDeclAttr::get(
91 builder.getContext(), builder.getStringAttr("WIDTH"),
92 builder.getI32Type(), builder.getI32IntegerAttr(numBits))));
93 Value value = instOp.getResult(0);
94
95 // Insert a bit cast if needed to obtain the original symbolic value's type.
96 if (op.getType() != value.getType())
97 value = BitcastOp::create(builder, op.getLoc(), op.getType(), value);
98
99 // Replace the `verif.symbolic_value` op.
100 op.replaceAllUsesWith(value);
101 op.erase();
102 return success();
103 });
104 return failure(result.wasInterrupted());
105}
106
107/// Replace `SymbolicValueOp`s with an `(* anyseq *)` wire declaration.
108void LowerSymbolicValuesPass::lowerToAnySeqWire() {
109 getOperation().walk([&](SymbolicValueOp op) {
110 // Create a replacement wire declaration with a `(* anyseq *)` Verilog
111 // attribute.
112 OpBuilder builder(op);
113 auto wireOp = sv::WireOp::create(builder, op.getLoc(),
114 sv::NetType::get(op.getType()));
115 sv::addSVAttributes(wireOp,
116 sv::SVAttributeAttr::get(&getContext(), "anyseq"));
117
118 // Create a read from the wire and replace the `verif.symbolic_value` op.
119 Value value = sv::ReadInOutOp::create(builder, op.getLoc(), wireOp);
120 op.replaceAllUsesWith(value);
121 op.erase();
122 });
123}
124
125/// Replace `SymbolicValueOp`s in `hw.module` bodies with input ports.
126LogicalResult LowerSymbolicValuesPass::lowerToHWInputs() {
127 auto module = getOperation();
128 DenseSet<StringAttr> referencedModules;
129 module.walk([&](InstanceOp op) {
130 referencedModules.insert(op.getReferencedModuleNameAttr());
131 });
132
133 auto result = module.walk([&](SymbolicValueOp op) -> WalkResult {
134 if (!op->getParentOfType<HWModuleOp>())
135 return op.emitError()
136 << "cannot lower symbolic value to hw.module input outside of an "
137 "hw.module";
138 return WalkResult::advance();
139 });
140 if (result.wasInterrupted())
141 return failure();
142
143 for (auto hwModule : module.getOps<HWModuleOp>()) {
144 SmallVector<SymbolicValueOp> symbolicValues;
145 hwModule.walk([&](SymbolicValueOp op) { symbolicValues.push_back(op); });
146 if (symbolicValues.empty())
147 continue;
148
149 if (referencedModules.contains(hwModule.getModuleNameAttr())) {
150 hwModule.emitError()
151 << "cannot lower symbolic values in instantiated module '"
152 << hwModule.getModuleName()
153 << "' to HW inputs; run the 'hw-input' lowering strategy after "
154 "flattening modules";
155 return failure();
156 }
157
158 for (auto symbolicValue : symbolicValues) {
159 auto [name, arg] = hwModule.insertInput(
160 hwModule.getNumInputPorts(),
161 StringAttr::get(module.getContext(), "symbolic_value"),
162 symbolicValue.getType());
163 (void)name;
164 symbolicValue.getResult().replaceAllUsesWith(arg);
165 symbolicValue.erase();
166 }
167 }
168
169 return success();
170}
false return failure()
Parse an optional keyword or string and set instance into 'result'.
return success()
create(data_type, value)
Definition hw.py:444
create(value)
Definition sv.py:151
create(data_type, name=None, sym_name=None)
Definition sv.py:63
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition hw.py:1
Definition verif.py:1