21 #include "mlir/IR/BuiltinOps.h"
22 #include "mlir/IR/Threading.h"
23 #include "mlir/Pass/Pass.h"
24 #include "mlir/Support/LogicalResult.h"
25 #include "llvm/ADT/MapVector.h"
29 #define GEN_PASS_DEF_LOWERDPI
30 #include "circt/Dialect/FIRRTL/Passes.h.inc"
36 using namespace circt;
40 struct LowerDPIPass :
public circt::firrtl::impl::LowerDPIBase<LowerDPIPass> {
41 void runOnOperation()
override;
46 LowerDPI(CircuitOp circuitOp) : circuitOp(circuitOp), nameSpace(circuitOp) {}
49 bool changed()
const {
return !funcNameToCallSites.empty(); }
53 void collectIntrinsics();
56 LogicalResult lower();
58 sim::DPIFuncOp getOrCreateDPIFuncDecl(DPICallIntrinsicOp op);
59 LogicalResult lowerDPIIntrinsic(DPICallIntrinsicOp op);
61 MapVector<StringAttr, SmallVector<DPICallIntrinsicOp>> funcNameToCallSites;
64 llvm::DenseMap<std::pair<StringAttr, Type>, sim::DPIFuncOp>
65 functionSignatureToDPIFuncOp;
67 firrtl::CircuitOp circuitOp;
72 void LowerDPI::collectIntrinsics() {
74 struct DpiCallCollections {
76 SmallVector<DPICallIntrinsicOp> dpiOps;
79 SmallVector<DpiCallCollections, 0> collections;
80 collections.reserve(64);
82 for (
auto module : circuitOp.getOps<FModuleOp>())
83 collections.push_back(DpiCallCollections{module, {}});
85 parallelForEach(circuitOp.getContext(), collections, [](
auto &result) {
87 [&](DPICallIntrinsicOp dpi) { result.dpiOps.push_back(dpi); });
90 for (
auto &collection : collections)
91 for (
auto dpi : collection.dpiOps)
92 funcNameToCallSites[dpi.getFunctionNameAttr()].push_back(dpi);
99 return loweredType.replace([](hw::ArrayType array) {
105 Value loweredValue) {
106 if (isa<IntegerType>(loweredValue.getType()))
109 auto array = dyn_cast<hw::ArrayType>(loweredValue.getType());
115 SmallVector<Value> values;
116 auto length = array.getNumElements();
117 auto width = llvm::Log2_64_Ceil(length);
120 for (
int i = length - 1; i >= 0; --i) {
126 values.push_back(elem);
129 return builder.create<sv::UnpackedArrayCreateOp>(
134 static Value
getLowered(ImplicitLocOpBuilder &builder, Value value) {
140 Value result = builder.create<mlir::UnrealizedConversionCastOp>(type, value)
152 mlir::emitError(value.getLoc())
153 <<
"contains a type that currently not supported";
157 return builder.create<sv::UnpackedOpenArrayCastOp>(dpiType, result);
160 LogicalResult LowerDPI::lower() {
161 for (
auto [name, calls] : funcNameToCallSites) {
162 auto firstDPICallop = calls.front();
164 auto firstDPIDecl = getOrCreateDPIFuncDecl(firstDPICallop);
166 auto inputTypes = firstDPICallop.getInputs().getTypes();
167 auto outputTypes = firstDPICallop.getResultTypes();
169 ImplicitLocOpBuilder builder(firstDPICallop.getLoc(),
170 circuitOp.getOperation());
171 auto lowerCall = [&](DPICallIntrinsicOp dpiOp) {
172 builder.setInsertionPoint(dpiOp);
173 auto clock =
getLowered(builder, dpiOp.getClock());
174 auto enable =
getLowered(builder, dpiOp.getEnable());
175 SmallVector<Value, 4> inputs;
176 inputs.reserve(dpiOp.getInputs().size());
177 for (
auto input : dpiOp.getInputs()) {
183 SmallVector<Type> outputTypes;
184 if (dpiOp.getResult())
185 outputTypes.push_back(
188 auto call = builder.create<sim::DPICallOp>(
189 outputTypes, firstDPIDecl.getSymNameAttr(), clock, enable, inputs);
190 if (!call.getResults().empty()) {
192 auto result = builder
193 .create<mlir::UnrealizedConversionCastOp>(
194 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)
235 sim::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)) {
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)) {
261 port.name = outputName ? outputName
262 : builder.getStringAttr(Twine(
"out_") + Twine(idx));
264 ports.push_back(port);
269 functionSignatureToDPIFuncOp.find({op.getFunctionNameAttr(), modType});
270 if (it != functionSignatureToDPIFuncOp.end())
273 auto funcSymbol = nameSpace.newName(op.getFunctionNameAttr().getValue());
274 auto funcOp = builder.create<sim::DPIFuncOp>(
275 funcSymbol, modType, ArrayAttr(), ArrayAttr(), op.getFunctionNameAttr());
278 functionSignatureToDPIFuncOp[{op.getFunctionNameAttr(), modType}] = funcOp;
287 void LowerDPIPass::runOnOperation() {
288 auto circuitOp = getOperation();
289 LowerDPI lowerDPI(circuitOp);
290 if (failed(lowerDPI.run()))
291 return signalPassFailure();
292 if (!lowerDPI.changed())
293 return markAllAnalysesPreserved();
297 return std::make_unique<LowerDPIPass>();
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)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
std::unique_ptr< mlir::Pass > createLowerDPIPass()
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.