CIRCT  20.0.0git
LowerDPIFunc.cpp
Go to the documentation of this file.
1 //===- LowerDPIFunc.cpp - Lower sim.dpi.func to func.func ----*- C++ -*-===//
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 //
9 // This pass lowers Sim DPI func ops to MLIR func and call.
10 //
11 // sim.dpi.func @foo(input %a: i32, output %b: i64)
12 // hw.module @top (..) {
13 // %result = sim.dpi.call @foo(%a) clock %clock
14 // }
15 //
16 // ->
17 //
18 // func.func @foo(%a: i32, %b: !llvm.ptr) // Output is passed by a reference.
19 // func.func @foo_wrapper(%a: i32) -> (i64) {
20 // %0 = llvm.alloca: !llvm.ptr
21 // %v = func.call @foo (%a, %0)
22 // func.return %v
23 // }
24 // hw.module @mod(..) {
25 // %result = sim.dpi.call @foo_wrapper(%a) clock %clock
26 // }
27 //===----------------------------------------------------------------------===//
28 
32 #include "mlir/Dialect/Func/IR/FuncOps.h"
33 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
34 #include "mlir/Dialect/LLVMIR/LLVMTypes.h"
35 #include "mlir/Transforms/DialectConversion.h"
36 #include "llvm/Support/Debug.h"
37 
38 #define DEBUG_TYPE "sim-lower-dpi-func"
39 
40 namespace circt {
41 namespace sim {
42 #define GEN_PASS_DEF_LOWERDPIFUNC
43 #include "circt/Dialect/Sim/SimPasses.h.inc"
44 } // namespace sim
45 } // namespace circt
46 
47 using namespace mlir;
48 using namespace circt;
49 
50 //===----------------------------------------------------------------------===//
51 // Pass Implementation
52 //===----------------------------------------------------------------------===//
53 
54 namespace {
55 
56 struct LoweringState {
57  DenseMap<StringAttr, func::FuncOp> dpiFuncDeclMapping;
58  circt::Namespace nameSpace;
59 };
60 
61 struct LowerDPIFuncPass : public sim::impl::LowerDPIFuncBase<LowerDPIFuncPass> {
62 
63  LogicalResult lowerDPI();
64  LogicalResult lowerDPIFuncOp(sim::DPIFuncOp simFunc,
65  LoweringState &loweringState,
66  SymbolTable &symbolTable);
67  void runOnOperation() override;
68 };
69 
70 } // namespace
71 
72 LogicalResult LowerDPIFuncPass::lowerDPIFuncOp(sim::DPIFuncOp simFunc,
73  LoweringState &loweringState,
74  SymbolTable &symbolTable) {
75  ImplicitLocOpBuilder builder(simFunc.getLoc(), simFunc);
76  auto moduleType = simFunc.getModuleType();
77 
78  llvm::SmallVector<Type> dpiFunctionArgumentTypes;
79  for (auto arg : moduleType.getPorts()) {
80  // TODO: Support a non-integer type.
81  if (!arg.type.isInteger())
82  return simFunc->emitError()
83  << "non-integer type argument is unsupported now";
84 
85  if (arg.dir == hw::ModulePort::Input)
86  dpiFunctionArgumentTypes.push_back(arg.type);
87  else
88  // Output must be passed by a reference.
89  dpiFunctionArgumentTypes.push_back(
90  LLVM::LLVMPointerType::get(arg.type.getContext()));
91  }
92 
93  auto funcType = builder.getFunctionType(dpiFunctionArgumentTypes, {});
94  func::FuncOp func;
95 
96  // Look up func.func by verilog name since the function name is equal to the
97  // symbol name in MLIR
98  if (auto verilogName = simFunc.getVerilogName()) {
99  func = symbolTable.lookup<func::FuncOp>(*verilogName);
100  // TODO: Check if function type matches.
101  }
102 
103  // If a referred function is not in the same module, create an external
104  // function declaration.
105  if (!func) {
106  func = builder.create<func::FuncOp>(simFunc.getVerilogName()
107  ? *simFunc.getVerilogName()
108  : simFunc.getSymName(),
109  funcType);
110  // External function needs to be private.
111  func.setPrivate();
112  }
113 
114  // Create a wrapper module that calls a DPI function.
115  auto funcOp = builder.create<func::FuncOp>(
116  loweringState.nameSpace.newName(simFunc.getSymName() + "_wrapper"),
117  moduleType.getFuncType());
118 
119  // Map old symbol to a new func op.
120  loweringState.dpiFuncDeclMapping[simFunc.getSymNameAttr()] = funcOp;
121 
122  builder.setInsertionPointToStart(funcOp.addEntryBlock());
123  SmallVector<Value> functionInputs;
124  SmallVector<LLVM::AllocaOp> functionOutputAllocas;
125 
126  size_t inputIndex = 0;
127  for (auto arg : moduleType.getPorts()) {
128  if (arg.dir == hw::ModulePort::InOut)
129  return funcOp->emitError() << "inout is currently not supported";
130 
131  if (arg.dir == hw::ModulePort::Input) {
132  functionInputs.push_back(funcOp.getArgument(inputIndex));
133  ++inputIndex;
134  } else {
135  // Allocate an output placeholder.
136  auto one = builder.create<LLVM::ConstantOp>(builder.getI64IntegerAttr(1));
137  auto alloca = builder.create<LLVM::AllocaOp>(
138  builder.getType<LLVM::LLVMPointerType>(), arg.type, one);
139  functionInputs.push_back(alloca);
140  functionOutputAllocas.push_back(alloca);
141  }
142  }
143 
144  builder.create<func::CallOp>(func, functionInputs);
145 
146  SmallVector<Value> results;
147  for (auto functionOutputAlloca : functionOutputAllocas)
148  results.push_back(builder.create<LLVM::LoadOp>(
149  functionOutputAlloca.getElemType(), functionOutputAlloca));
150 
151  builder.create<func::ReturnOp>(results);
152 
153  simFunc.erase();
154  return success();
155 }
156 
157 LogicalResult LowerDPIFuncPass::lowerDPI() {
158  LLVM_DEBUG(llvm::dbgs() << "Lowering sim DPI func to func.func\n");
159  auto op = getOperation();
160  LoweringState state;
161  state.nameSpace.add(op);
162  auto &symbolTable = getAnalysis<SymbolTable>();
163  for (auto simFunc : llvm::make_early_inc_range(op.getOps<sim::DPIFuncOp>()))
164  if (failed(lowerDPIFuncOp(simFunc, state, symbolTable)))
165  return failure();
166 
167  op.walk([&](sim::DPICallOp op) {
168  auto func = state.dpiFuncDeclMapping.at(op.getCalleeAttr().getAttr());
169  op.setCallee(func.getSymNameAttr());
170  });
171  return success();
172 }
173 
174 void LowerDPIFuncPass::runOnOperation() {
175  if (failed(lowerDPI()))
176  return signalPassFailure();
177 }
@ Input
Definition: HW.h:35
@ InOut
Definition: HW.h:35
std::shared_ptr< calyx::CalyxLoweringState > loweringState
A namespace that is used to store existing names and generate new names in some scope within the IR.
Definition: Namespace.h:30
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:55
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21