[Mlir-commits] [mlir] [mlir][docs] Add C example for C-compatible wrapper for LLVM IR (PR #120955)

Hongren Zheng llvmlistbot at llvm.org
Mon Dec 23 01:47:59 PST 2024


https://github.com/ZenithalHourlyRate created https://github.com/llvm/llvm-project/pull/120955

`TargetLLVMIR` documentation introduced the C-compatible wrapper function for a MLIR function and ways to generate it, but did not demonstrate the corresponding C function signature for them.

The C function signature is not obvious, in that
* `MemrefDescriptor` should be passed as _pointer_.
  + For example, MLIR function could return a new Descriptor, so pointer is a must.
  + Surprisingly, directly pass the struct, by C convention, is also a pointer so some function will work, but that is implicit and error-prone.
* for `@foo() -> memref<>`, the return type becomes the first argument in `_mlir_ciface_foo(%arg0: !llvm.ptr)`.
  + This is described in https://github.com/llvm/llvm-project/blob/f70ab7d909d6861c7eec5ab40679bde16ab826c6/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp#L110-L167 Especially by code `size_t argOffset = resultStructType ? 1 : 0;` saying the actual argument starts at 1 when result is a struct (memref)

Users using the wrong signature will get incorrect results. LLVM discourse has some example of it
* https://discourse.llvm.org/t/how-to-compile-and-link-with-other-c-c-programs/4835/10
* https://discourse.llvm.org/t/segmentation-fault-on-memref-store/80286/3
* https://discourse.llvm.org/t/memref-store-storing-a-memref-load/80307

Cc @ftynse for relevent commit history. Cc @charitha22 and @Wheest from discourse post.



>From 5d468bbd018730a6b03ebc28149cdd7d24f1bd7f Mon Sep 17 00:00:00 2001
From: Zenithal <i at zenithal.me>
Date: Mon, 23 Dec 2024 09:25:33 +0000
Subject: [PATCH] [mlir][docs] Add C example for C-compatible wrapper for LLVM
 IR

---
 mlir/docs/TargetLLVMIR.md | 32 +++++++++++++++++++++++++++++---
 1 file changed, 29 insertions(+), 3 deletions(-)

diff --git a/mlir/docs/TargetLLVMIR.md b/mlir/docs/TargetLLVMIR.md
index 96a4589eb80e75..ed58040e1abbb8 100644
--- a/mlir/docs/TargetLLVMIR.md
+++ b/mlir/docs/TargetLLVMIR.md
@@ -646,7 +646,7 @@ Examples:
 
 ```mlir
 
-func.func @qux(%arg0: memref<?x?xf32>)
+func.func @qux(%arg0: memref<?x?xf32>) attributes {llvm.emit_c_interface}
 
 // Gets converted into the following
 // (using type alias for brevity):
@@ -683,8 +683,18 @@ llvm.func @qux(%arg0: !llvm.ptr, %arg1: !llvm.ptr,
 llvm.func @_mlir_ciface_qux(!llvm.ptr)
 ```
 
+
+```cpp
+// The C function implementation for the interface function
+extern "C" {
+void _mlir_ciface_qux(MemRefDescriptor<float, 2> *input) {
+  // detailed impl
+}
+}
+```
+
 ```mlir
-func.func @foo(%arg0: memref<?x?xf32>) {
+func.func @foo(%arg0: memref<?x?xf32>) attributes {llvm.emit_c_interface} {
   return
 }
 
@@ -719,8 +729,15 @@ llvm.func @_mlir_ciface_foo(%arg0: !llvm.ptr) {
 }
 ```
 
+```cpp
+// The C function signature for the interface function
+extern "C" {
+void _mlir_ciface_foo(MemRefDescriptor<float, 2> *input);
+}
+```
+
 ```mlir
-func.func @foo(%arg0: memref<?x?xf32>) -> memref<?x?xf32> {
+func.func @foo(%arg0: memref<?x?xf32>) -> memref<?x?xf32> attributes {llvm.emit_c_interface} {
   return %arg0 : memref<?x?xf32>
 }
 
@@ -744,6 +761,7 @@ llvm.func @foo(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: i64,
 }
 
 // Interface function callable from C.
+// NOTE that the returned memref becomes the first argument
 llvm.func @_mlir_ciface_foo(%arg0: !llvm.ptr, %arg1: !llvm.ptr) {
   %0 = llvm.load %arg1 : !llvm.ptr
   %1 = llvm.extractvalue %0[0] : !llvm.memref_2d
@@ -760,6 +778,14 @@ llvm.func @_mlir_ciface_foo(%arg0: !llvm.ptr, %arg1: !llvm.ptr) {
 }
 ```
 
+```cpp
+// The C function signature for the interface function
+extern "C" {
+void _mlir_ciface_foo(MemRefDescriptor<float, 2> *output,
+                      MemRefDescriptor<float, 2> *input);
+}
+```
+
 Rationale: Introducing auxiliary functions for C-compatible interfaces is
 preferred to modifying the calling convention since it will minimize the effect
 of C compatibility on intra-module calls or calls between MLIR-generated



More information about the Mlir-commits mailing list