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
12#include "llvm/ADT/DenseSet.h"
13
14using namespace circt;
15using namespace mlir;
16using namespace verif;
17using namespace hw;
18
19namespace circt {
20namespace verif {
21#define GEN_PASS_DEF_LOWERSYMBOLICVALUESPASS
22#include "circt/Dialect/Verif/Passes.h.inc"
23} // namespace verif
24} // namespace circt
25
26namespace {
27struct LowerSymbolicValuesPass
28 : verif::impl::LowerSymbolicValuesPassBase<LowerSymbolicValuesPass> {
29 using LowerSymbolicValuesPassBase::LowerSymbolicValuesPassBase;
30 void runOnOperation() override;
31 LogicalResult lowerToExtModule();
32 void lowerToAnySeqWire();
33 LogicalResult lowerToHWInputs();
34};
35} // namespace
36
37void LowerSymbolicValuesPass::runOnOperation() {
38 switch (mode) {
39 case SymbolicValueLowering::ExtModule:
40 if (failed(lowerToExtModule()))
41 signalPassFailure();
42 break;
43 case SymbolicValueLowering::Yosys:
44 lowerToAnySeqWire();
45 break;
46 case SymbolicValueLowering::HWInput:
47 if (failed(lowerToHWInputs()))
48 signalPassFailure();
49 break;
50 }
51}
52
53/// Replace all `SymbolicValueOp`s with instances of corresponding extmodules.
54/// This allows tools to treat the modules as blackboxes, or definitions of the
55/// modules may be provided later by the user.
56LogicalResult LowerSymbolicValuesPass::lowerToExtModule() {
57 auto &symbolTable = getAnalysis<SymbolTable>();
58 DenseMap<Type, HWModuleExternOp> extmoduleOps;
59 auto result = getOperation().walk([&](SymbolicValueOp op) -> WalkResult {
60 // Determine the number of bits needed for the symbolic value.
61 auto numBits = hw::getBitWidth(op.getType());
62 if (numBits < 0)
63 return op.emitError() << "symbolic value bit width unknown";
64
65 // If we don't already have an extmodule for this number of bits, create
66 // one.
67 auto builder = OpBuilder::atBlockEnd(getOperation().getBody());
68 auto flatType = builder.getIntegerType(numBits);
69 auto &extmoduleOp = extmoduleOps[flatType];
70 if (!extmoduleOp) {
71 extmoduleOp = HWModuleExternOp::create(
72 builder, op.getLoc(),
73 builder.getStringAttr(Twine("circt.symbolic_value.") +
74 Twine(numBits)),
75 PortInfo{{builder.getStringAttr("z"), flatType, ModulePort::Output}},
76 "circt_symbolic_value",
77 builder.getArrayAttr(ParamDeclAttr::get(
78 builder.getContext(), builder.getStringAttr("WIDTH"),
79 builder.getI32Type(), Attribute())));
80 symbolTable.insert(extmoduleOp);
81 }
82
83 // Instantiate the extmodule as a means of generating a symbolic value with
84 // the correct number of bits.
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);
93
94 // Insert a bit cast if needed to obtain the original symbolic value's type.
95 if (op.getType() != value.getType())
96 value = BitcastOp::create(builder, op.getLoc(), op.getType(), value);
97
98 // Replace the `verif.symbolic_value` op.
99 op.replaceAllUsesWith(value);
100 op.erase();
101 return success();
102 });
103 return failure(result.wasInterrupted());
104}
105
106/// Replace `SymbolicValueOp`s with an `(* anyseq *)` wire declaration.
107void LowerSymbolicValuesPass::lowerToAnySeqWire() {
108 getOperation().walk([&](SymbolicValueOp op) {
109 // Create a replacement wire declaration with a `(* anyseq *)` Verilog
110 // attribute.
111 OpBuilder builder(op);
112 auto wireOp = sv::WireOp::create(builder, op.getLoc(), op.getType());
113 sv::addSVAttributes(wireOp,
114 sv::SVAttributeAttr::get(&getContext(), "anyseq"));
115
116 // Create a read from the wire and replace the `verif.symbolic_value` op.
117 Value value = sv::ReadInOutOp::create(builder, op.getLoc(), wireOp);
118 op.replaceAllUsesWith(value);
119 op.erase();
120 });
121}
122
123/// Replace `SymbolicValueOp`s in `hw.module` bodies with input ports.
124LogicalResult LowerSymbolicValuesPass::lowerToHWInputs() {
125 auto module = getOperation();
126 DenseSet<StringAttr> referencedModules;
127 module.walk([&](InstanceOp op) {
128 referencedModules.insert(op.getReferencedModuleNameAttr());
129 });
130
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 "
135 "hw.module";
136 return WalkResult::advance();
137 });
138 if (result.wasInterrupted())
139 return failure();
140
141 for (auto hwModule : module.getOps<HWModuleOp>()) {
142 SmallVector<SymbolicValueOp> symbolicValues;
143 hwModule.walk([&](SymbolicValueOp op) { symbolicValues.push_back(op); });
144 if (symbolicValues.empty())
145 continue;
146
147 if (referencedModules.contains(hwModule.getModuleNameAttr())) {
148 hwModule.emitError()
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";
153 return failure();
154 }
155
156 for (auto symbolicValue : symbolicValues) {
157 auto [name, arg] = hwModule.insertInput(
158 hwModule.getNumInputPorts(),
159 StringAttr::get(module.getContext(), "symbolic_value"),
160 symbolicValue.getType());
161 (void)name;
162 symbolicValue.getResult().replaceAllUsesWith(arg);
163 symbolicValue.erase();
164 }
165 }
166
167 return success();
168}
create(data_type, value)
Definition hw.py:441
create(value)
Definition sv.py:108
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
This holds the name, type, direction of a module's ports.