Loading [MathJax]/extensions/tex2jax.js
CIRCT 22.0.0git
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 = func::FuncOp::create(builder,
107 simFunc.getVerilogName()
108 ? *simFunc.getVerilogName()
109 : simFunc.getSymName(),
110 funcType);
111 // External function needs to be private.
112 func.setPrivate();
113 }
114
115 // Create a wrapper module that calls a DPI function.
116 auto funcOp = func::FuncOp::create(
117 builder,
118 loweringState.nameSpace.newName(simFunc.getSymName() + "_wrapper"),
119 moduleType.getFuncType());
120
121 // Map old symbol to a new func op.
122 loweringState.dpiFuncDeclMapping[simFunc.getSymNameAttr()] = funcOp;
123
124 builder.setInsertionPointToStart(funcOp.addEntryBlock());
125 SmallVector<Value> functionInputs;
126 SmallVector<LLVM::AllocaOp> functionOutputAllocas;
127
128 size_t inputIndex = 0;
129 for (auto arg : moduleType.getPorts()) {
130 if (arg.dir == hw::ModulePort::InOut)
131 return funcOp->emitError() << "inout is currently not supported";
132
133 if (arg.dir == hw::ModulePort::Input) {
134 functionInputs.push_back(funcOp.getArgument(inputIndex));
135 ++inputIndex;
136 } else {
137 // Allocate an output placeholder.
138 auto one =
139 LLVM::ConstantOp::create(builder, builder.getI64IntegerAttr(1));
140 auto alloca = LLVM::AllocaOp::create(
141 builder, builder.getType<LLVM::LLVMPointerType>(), arg.type, one);
142 functionInputs.push_back(alloca);
143 functionOutputAllocas.push_back(alloca);
144 }
145 }
146
147 func::CallOp::create(builder, func, functionInputs);
148
149 SmallVector<Value> results;
150 for (auto functionOutputAlloca : functionOutputAllocas)
151 results.push_back(LLVM::LoadOp::create(
152 builder, functionOutputAlloca.getElemType(), functionOutputAlloca));
153
154 func::ReturnOp::create(builder, results);
155
156 simFunc.erase();
157 return success();
158}
159
160LogicalResult LowerDPIFuncPass::lowerDPI() {
161 LLVM_DEBUG(llvm::dbgs() << "Lowering sim DPI func to func.func\n");
162 auto op = getOperation();
163 LoweringState state;
164 state.nameSpace.add(op);
165 auto &symbolTable = getAnalysis<SymbolTable>();
166 for (auto simFunc : llvm::make_early_inc_range(op.getOps<sim::DPIFuncOp>()))
167 if (failed(lowerDPIFuncOp(simFunc, state, symbolTable)))
168 return failure();
169
170 op.walk([&](sim::DPICallOp op) {
171 auto func = state.dpiFuncDeclMapping.at(op.getCalleeAttr().getAttr());
172 op.setCallee(func.getSymNameAttr());
173 });
174 return success();
175}
176
177void LowerDPIFuncPass::runOnOperation() {
178 if (failed(lowerDPI()))
179 return signalPassFailure();
180}
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.