CIRCT 20.0.0git
Loading...
Searching...
No Matches
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
40namespace circt {
41namespace sim {
42#define GEN_PASS_DEF_LOWERDPIFUNC
43#include "circt/Dialect/Sim/SimPasses.h.inc"
44} // namespace sim
45} // namespace circt
46
47using namespace mlir;
48using namespace circt;
49
50//===----------------------------------------------------------------------===//
51// Pass Implementation
52//===----------------------------------------------------------------------===//
53
54namespace {
55
56struct LoweringState {
57 DenseMap<StringAttr, func::FuncOp> dpiFuncDeclMapping;
58 circt::Namespace nameSpace;
59};
60
61struct 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
72LogicalResult 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
157LogicalResult 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
174void LowerDPIFuncPass::runOnOperation() {
175 if (failed(lowerDPI()))
176 return signalPassFailure();
177}
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
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.