[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