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);
 
   133static Value 
getLowered(ImplicitLocOpBuilder &builder, Value value) {
…}
  
  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.