[Mlir-commits] [mlir] add9f1a - [mlir][LLVM] Finer-grained control for C interface emission
Nicolas Vasilache
llvmlistbot at llvm.org
Thu Apr 2 10:08:58 PDT 2020
Author: Nicolas Vasilache
Date: 2020-04-02T13:07:10-04:00
New Revision: add9f1a5dc1963149dac4cb8b25bf2cb825a02c2
URL: https://github.com/llvm/llvm-project/commit/add9f1a5dc1963149dac4cb8b25bf2cb825a02c2
DIFF: https://github.com/llvm/llvm-project/commit/add9f1a5dc1963149dac4cb8b25bf2cb825a02c2.diff
LOG: [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.
Added:
Modified:
mlir/docs/ConversionToLLVMDialect.md
mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp
mlir/test/Conversion/StandardToLLVM/calling-convention.mlir
Removed:
################################################################################
diff --git a/mlir/docs/ConversionToLLVMDialect.md b/mlir/docs/ConversionToLLVMDialect.md
index 92be9a5a3be0..15d09cb4b87a 100644
--- a/mlir/docs/ConversionToLLVMDialect.md
+++ b/mlir/docs/ConversionToLLVMDialect.md
@@ -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
diff --git a/mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp b/mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp
index d840a87568a7..12fc8b177c17 100644
--- a/mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp
+++ b/mlir/lib/Conversion/StandardToLLVM/StandardToLLVM.cpp
@@ -932,6 +932,7 @@ struct FuncOpConversionBase : public ConvertOpToLLVMPattern<FuncOp> {
/// 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
diff --git a/mlir/test/Conversion/StandardToLLVM/calling-convention.mlir b/mlir/test/Conversion/StandardToLLVM/calling-convention.mlir
index 348afff33967..87bdab2680f9 100644
--- a/mlir/test/Conversion/StandardToLLVM/calling-convention.mlir
+++ b/mlir/test/Conversion/StandardToLLVM/calling-convention.mlir
@@ -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
More information about the Mlir-commits
mailing list