forked from OSchip/llvm-project
[mlir][LLVM] Finer-grained control for C interface emission
C interface emission is controlled by a flag and has coarse granularity. With this coarse control, interfaces are emitted for all external functions. This makes is easy to get undefined symbols. This revision adds support for controlling per-function emission with an "emit_c_interface" attribute.
This commit is contained in:
parent
12fcbcecff
commit
add9f1a5dc
|
@ -374,12 +374,14 @@ overridden by the user.*
|
|||
|
||||
### C-compatible wrapper emission
|
||||
|
||||
In practical cases, it may be desirable to have externally-facing functions
|
||||
with a single attribute corresponding to a MemRef argument. When interfacing
|
||||
with LLVM IR produced from C, the code needs to respect the corresponding
|
||||
calling convention. The conversion to the LLVM dialect provides an option to
|
||||
generate wrapper functions that take memref descriptors as pointers-to-struct
|
||||
compatible with data types produced by Clang when compiling C sources.
|
||||
In practical cases, it may be desirable to have externally-facing functions with
|
||||
a single attribute corresponding to a MemRef argument. When interfacing with
|
||||
LLVM IR produced from C, the code needs to respect the corresponding calling
|
||||
convention. The conversion to the LLVM dialect provides an option to generate
|
||||
wrapper functions that take memref descriptors as pointers-to-struct compatible
|
||||
with data types produced by Clang when compiling C sources. The generation of
|
||||
such wrapper functions can additionally be controlled at a function granularity
|
||||
by setting the `llvm.emit_c_interface` unit attribute.
|
||||
|
||||
More specifically, a memref argument is converted into a pointer-to-struct
|
||||
argument of type `{T*, T*, i64, i64[N], i64[N]}*` in the wrapper function, where
|
||||
|
|
|
@ -932,6 +932,7 @@ protected:
|
|||
/// FuncOp legalization pattern that converts MemRef arguments to pointers to
|
||||
/// MemRef descriptors (LLVM struct data types) containing all the MemRef type
|
||||
/// information.
|
||||
static constexpr StringRef kEmitIfaceAttrName = "llvm.emit_c_interface";
|
||||
struct FuncOpConversion : public FuncOpConversionBase {
|
||||
FuncOpConversion(LLVMTypeConverter &converter, bool emitCWrappers)
|
||||
: FuncOpConversionBase(converter), emitWrappers(emitCWrappers) {}
|
||||
|
@ -942,7 +943,7 @@ struct FuncOpConversion : public FuncOpConversionBase {
|
|||
auto funcOp = cast<FuncOp>(op);
|
||||
|
||||
auto newFuncOp = convertFuncOpToLLVMFuncOp(funcOp, rewriter);
|
||||
if (emitWrappers) {
|
||||
if (emitWrappers || funcOp.getAttrOfType<UnitAttr>(kEmitIfaceAttrName)) {
|
||||
if (newFuncOp.isExternal())
|
||||
wrapExternalFunction(rewriter, op->getLoc(), typeConverter, funcOp,
|
||||
newFuncOp);
|
||||
|
@ -2821,7 +2822,6 @@ struct LLVMLoweringPass : public ModulePass<LLVMLoweringPass> {
|
|||
if (failed(applyPartialConversion(m, target, patterns, &typeConverter)))
|
||||
signalPassFailure();
|
||||
}
|
||||
|
||||
};
|
||||
} // end namespace
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// RUN: mlir-opt -convert-std-to-llvm='emit-c-wrappers=1' %s | FileCheck %s
|
||||
// RUN: mlir-opt -convert-std-to-llvm %s | FileCheck %s --check-prefix=EMIT_C_ATTRIBUTE
|
||||
|
||||
// This tests the default memref calling convention and the emission of C
|
||||
// wrappers. We don't need to separate runs because the wrapper-emission
|
||||
|
@ -72,6 +73,7 @@ func @caller() {
|
|||
}
|
||||
|
||||
// CHECK-LABEL: @callee
|
||||
// EMIT_C_ATTRIBUTE-LABEL: @callee
|
||||
func @callee(%arg0: memref<?xf32>, %arg1: index) {
|
||||
%0 = load %arg0[%arg1] : memref<?xf32>
|
||||
return
|
||||
|
@ -93,3 +95,17 @@ func @callee(%arg0: memref<?xf32>, %arg1: index) {
|
|||
// Forward the descriptor components to the call.
|
||||
// CHECK: llvm.call @callee(%[[ALLOC]], %[[ALIGN]], %[[OFFSET]], %[[SIZE]], %[[STRIDE]], %{{.*}}) : (!llvm<"float*">, !llvm<"float*">, !llvm.i64, !llvm.i64, !llvm.i64, !llvm.i64) -> ()
|
||||
|
||||
// EMIT_C_ATTRIBUTE-NOT: @mlir_ciface_callee
|
||||
|
||||
// CHECK-LABEL: @other_callee
|
||||
// EMIT_C_ATTRIBUTE-LABEL: @other_callee
|
||||
func @other_callee(%arg0: memref<?xf32>, %arg1: index) attributes { llvm.emit_c_interface } {
|
||||
%0 = load %arg0[%arg1] : memref<?xf32>
|
||||
return
|
||||
}
|
||||
|
||||
// CHECK: @_mlir_ciface_other_callee
|
||||
// CHECK: llvm.call @other_callee
|
||||
|
||||
// EMIT_C_ATTRIBUTE: @_mlir_ciface_other_callee
|
||||
// EMIT_C_ATTRIBUTE: llvm.call @other_callee
|
||||
|
|
Loading…
Reference in New Issue