[Mlir-commits] [mlir] [mlir][docs] Add C example for C-compatible wrapper for LLVM IR (PR #120955)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Mon Dec 23 01:48:35 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir
Author: Hongren Zheng (ZenithalHourlyRate)
<details>
<summary>Changes</summary>
`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.
---
Full diff: https://github.com/llvm/llvm-project/pull/120955.diff
1 Files Affected:
- (modified) mlir/docs/TargetLLVMIR.md (+29-3)
``````````diff
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
``````````
</details>
https://github.com/llvm/llvm-project/pull/120955
More information about the Mlir-commits
mailing list