19#include "mlir/IR/BuiltinOps.h"
20#include "mlir/IR/Threading.h"
21#include "mlir/Pass/Pass.h"
22#include "mlir/Support/LogicalResult.h"
23#include "llvm/ADT/MapVector.h"
27#define GEN_PASS_DEF_LOWERDPI
28#include "circt/Dialect/FIRRTL/Passes.h.inc"
38struct LowerDPIPass :
public circt::firrtl::impl::LowerDPIBase<LowerDPIPass> {
39 void runOnOperation()
override;
44 LowerDPI(CircuitOp circuitOp) : circuitOp(circuitOp), nameSpace(circuitOp) {}
47 bool changed()
const {
return !funcNameToCallSites.empty(); }
51 void collectIntrinsics();
54 LogicalResult lower();
56 sim::DPIFuncOp getOrCreateDPIFuncDecl(DPICallIntrinsicOp op);
57 LogicalResult lowerDPIIntrinsic(DPICallIntrinsicOp op);
59 MapVector<StringAttr, SmallVector<DPICallIntrinsicOp>> funcNameToCallSites;
62 llvm::DenseMap<std::pair<StringAttr, Type>, sim::DPIFuncOp>
63 functionSignatureToDPIFuncOp;
65 firrtl::CircuitOp circuitOp;
70void LowerDPI::collectIntrinsics() {
72 struct DpiCallCollections {
74 SmallVector<DPICallIntrinsicOp> dpiOps;
77 SmallVector<DpiCallCollections, 0> collections;
78 collections.reserve(64);
80 for (
auto module : circuitOp.getOps<FModuleOp>())
81 collections.push_back(DpiCallCollections{module, {}});
83 parallelForEach(circuitOp.getContext(), collections, [](
auto &result) {
85 [&](DPICallIntrinsicOp dpi) { result.dpiOps.push_back(dpi); });
88 for (
auto &collection : collections)
89 for (auto dpi : collection.dpiOps)
90 funcNameToCallSites[dpi.getFunctionNameAttr()].push_back(dpi);
97 return loweredType.replace([](hw::ArrayType array) {
98 return sv::UnpackedOpenArrayType::get(array.getElementType());
103 Value loweredValue) {
104 if (isa<IntegerType>(loweredValue.getType()))
107 auto array = dyn_cast<hw::ArrayType>(loweredValue.getType());
113 SmallVector<Value> values;
114 auto length = array.getNumElements();
115 auto width = llvm::Log2_64_Ceil(length);
118 for (
int i = length - 1; i >= 0; --i) {
124 values.push_back(elem);
127 return sv::UnpackedArrayCreateOp::create(
129 hw::UnpackedArrayType::get(
lowerType(array.getElementType()), length),
133static Value
getLowered(ImplicitLocOpBuilder &builder, Value value) {
139 Value result = mlir::UnrealizedConversionCastOp::create(builder, type, value)
151 mlir::emitError(value.getLoc())
152 <<
"contains a type that currently not supported";
156 return sv::UnpackedOpenArrayCastOp::create(builder, dpiType, result);
159LogicalResult LowerDPI::lower() {
160 for (
auto [name, calls] : funcNameToCallSites) {
161 auto firstDPICallop = calls.front();
163 auto firstDPIDecl = getOrCreateDPIFuncDecl(firstDPICallop);
165 auto inputTypes = firstDPICallop.getInputs().getTypes();
166 auto outputTypes = firstDPICallop.getResultTypes();
168 ImplicitLocOpBuilder builder(firstDPICallop.getLoc(),
169 circuitOp.getOperation());
170 auto lowerCall = [&](DPICallIntrinsicOp dpiOp) {
171 builder.setInsertionPoint(dpiOp);
172 auto clock =
getLowered(builder, dpiOp.getClock());
173 auto enable =
getLowered(builder, dpiOp.getEnable());
174 SmallVector<Value, 4> inputs;
175 inputs.reserve(dpiOp.getInputs().size());
176 for (
auto input : dpiOp.getInputs()) {
182 SmallVector<Type> outputTypes;
183 if (dpiOp.getResult())
184 outputTypes.push_back(
187 auto call = sim::DPICallOp::create(builder, outputTypes,
188 firstDPIDecl.getSymNameAttr(), clock,
190 if (!call.getResults().empty()) {
193 mlir::UnrealizedConversionCastOp::create(
194 builder, dpiOp.getResult().getType(), call.getResult(0))
196 dpiOp.getResult().replaceAllUsesWith(result);
201 if (failed(lowerCall(firstDPICallop)))
204 for (
auto dpiOp :
llvm::ArrayRef(calls).drop_front()) {
208 if (dpiOp.getInputs().getTypes() != inputTypes) {
209 auto diag = firstDPICallop.emitOpError()
210 <<
"DPI function " << firstDPICallop.getFunctionNameAttr()
211 <<
" input types don't match ";
212 diag.attachNote(dpiOp.getLoc()) <<
" mismatched caller is here";
216 if (dpiOp.getResultTypes() != outputTypes) {
217 auto diag = firstDPICallop.emitOpError()
218 <<
"DPI function " << firstDPICallop.getFunctionNameAttr()
219 <<
" output types don't match";
220 diag.attachNote(dpiOp.getLoc()) <<
" mismatched caller is here";
224 if (failed(lowerCall(dpiOp)))
228 for (
auto callOp : calls)
235sim::DPIFuncOp LowerDPI::getOrCreateDPIFuncDecl(DPICallIntrinsicOp op) {
236 ImplicitLocOpBuilder builder(op.getLoc(), circuitOp.getOperation());
237 builder.setInsertionPointToStart(circuitOp.getBodyBlock());
238 auto inputTypes = op.getInputs().getTypes();
239 auto outputTypes = op.getResultTypes();
240 ArrayAttr inputNames = op.getInputNamesAttr();
241 StringAttr outputName = op.getOutputNameAttr();
242 assert(outputTypes.size() <= 1);
244 SmallVector<hw::ModulePort> ports;
245 ports.reserve(inputTypes.size() + outputTypes.size());
248 for (
auto [idx, inType] :
llvm::enumerate(inputTypes)) {
250 port.
dir = hw::ModulePort::Direction::Input;
251 port.
name = inputNames ? cast<StringAttr>(inputNames[idx])
252 : builder.getStringAttr(Twine(
"in_") + Twine(idx));
254 ports.push_back(port);
258 for (
auto [idx, outType] :
llvm::enumerate(outputTypes)) {
260 port.
dir = hw::ModulePort::Direction::Output;
261 port.
name = outputName ? outputName
262 : builder.getStringAttr(Twine(
"out_") + Twine(idx));
264 ports.push_back(port);
267 auto modType = hw::ModuleType::get(builder.getContext(), ports);
269 functionSignatureToDPIFuncOp.find({op.getFunctionNameAttr(), modType});
270 if (it != functionSignatureToDPIFuncOp.end())
273 auto funcSymbol = nameSpace.newName(op.getFunctionNameAttr().getValue());
275 sim::DPIFuncOp::create(builder, funcSymbol, modType, ArrayAttr(),
276 ArrayAttr(), op.getFunctionNameAttr());
279 functionSignatureToDPIFuncOp[{op.getFunctionNameAttr(), modType}] = funcOp;
283LogicalResult LowerDPI::run() {
288void LowerDPIPass::runOnOperation() {
289 auto circuitOp = getOperation();
290 LowerDPI lowerDPI(circuitOp);
291 if (failed(lowerDPI.run()))
292 return signalPassFailure();
293 if (!lowerDPI.changed())
294 return markAllAnalysesPreserved();
assert(baseType &&"element must be base type")
static Value getLowered(ImplicitLocOpBuilder &builder, Value value)
static Type lowerDPIArgumentType(Type type)
static Value convertToUnpackedArray(ImplicitLocOpBuilder &builder, Value loweredValue)
Type lowerType(Type type, std::optional< Location > loc={}, llvm::function_ref< hw::TypeAliasType(Type, BaseTypeAliasType, Location)> getTypeDeclFn={})
Given a type, return the corresponding lowered type for the HW dialect.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
int run(Type[Generator] generator=CppGenerator, cmdline_args=sys.argv)
The namespace of a CircuitOp, generally inhabited by modules.