<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/83599>83599</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Confusing semantics for MLIR Python API for ExecutionEngine
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            mlir
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          fzakaria
      </td>
    </tr>
</table>

<pre>
    Hi !

I wanted to document the confusing Python API for ExecutionEngine that we encountered. 
It took us a while (CC @alexander-shaposhnikov ) to debug and thought I'd bring it up here.

Here is the first small example:
```python
text=r"""
module {
  llvm.func @_mlir_ciface_add(%arg0: f32, %arg1: f32) -> f32 attributes {llvm.emit_c_interface} {
    %0 = llvm.fadd %arg0, %arg1 : f32
 llvm.return %0 : f32
  }
}
"""

with Context():
 module = Module.parse(text)
    execution_engine = ExecutionEngine(module)
    args = [byref(c_float(1)), byref(c_float(2))]
    res = c_float(-1)
 execution_engine.invoke("add", *args, byref(res))
 print(res.value)
```

This example takes 2 arguments and sums them. Although we are passing f32 we have to pass them by pointer which seems unecessary; in any case it's understandable to make it a pointer (or _byref_).

The return value has to be written to, so that makes a lot more sense that it has to be a pointer.

The more confusing sample is if we expect multiple return values in MLIR.
I noticed if you have a function in MLIR which returns multiple values it gets lowered to LLVM struct.
We were not sure how to properly get access to this struct result from the ExecutionEngine.
```
  llvm.func @_mlir_ciface_add(%arg0: !llvm.ptr) attributes {llvm.emit_c_interface} {
    %0 = llvm.call @add() : () -> !llvm.struct<(f32, f32)>
    llvm.store %0, %arg0 : !llvm.struct<(f32, f32)>, !llvm.ptr
    llvm.return
 }
```

@alexander-shaposhnikov wrote a great minimal demo:

```
text=r"""
module {
  llvm.func @_mlir_ciface_add(%arg0: !llvm.ptr) attributes {llvm.emit_c_interface} {
 %0 = llvm.mlir.constant(1.000000e+00 : f32) : f32
    llvm.store %0, %arg0 : f32, !llvm.ptr
    llvm.return
 }
}

"""

with Context():
    module = Module.parse(text)
    execution_engine = ExecutionEngine(module)
 rp = c_float
    res = rp()
    execution_engine.invoke("add", pointer(pointer((res))))
    print(res.value)
```

The surprising thing was that we had to pas the result type had to be passed as a **double pointer**.
That part is unclear to me.

Finally, you have to build all this code up to handle putting the result either as the **last** argument or **first** argument depending if the MLIR function you are calling returns 1 or N items. This has made the code more confusing than it needs to be.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJy8V11v27gS_TX0yyCCTNmx_OCHJE7QAO1FcXFx99GgxZHFjUQK5CiO99cvhpIlO2m76Ba7heEy5PDMB4fn0CoEc7CIG7G8F8vtTHVUOb8p_1Avyhs12zt92nwyIORcpFuR3vXfz3BUllADOdCu6Bq0BFQhFM6WXTD2AF9PVDkLd1-foXQeHt-w6Mg4-2gPxiJQpQiOCGgL11lCjzqBAZyAnHuBLoCCY2VqBCHzhwcQi1TV-KasRn8TKtW6UFnz4l5ByHUMBffdAZTVQJXrDhXBs5ArDXvPERmCroUKPSaXuXxCj2BCDL80PhCERtU14Jtq2hpFNtiJ27T_tDGzfpLwjUS29ULK4ROnG6c7Dnt13_8NUNevTVJ2tuAsdk1t_K4wpSpwp7QWMhdyqfwhFdkdlJkU8gH6mfk4s4YbkT3yGBSRN_uOMLCLCI2NoV2xM1xKhhWr7aV7YLgURLYdIlFaw9nn5AzO3vpt0dQjdd6e918ug1hth9qMg-s69N9HQxU8OBuLxamux6LCuVLZFr7EYdIqH1DIvLdeTxnguYV22PcQb3rXV0LmPeLVTuUPIVqL5f3-5LEUMi92Ze0UxzNnW_48wMdFOSwutxOcxx5tsrqZT_7eh5kY--peMCYu42EPx3vHYV169RgGbz1S642lfj55VXU3JTX24mWZ_1eZcO5aIPWCASSnHm9niNcidE1s9CaBu7q_I3wJlUdomQrsIfbXEaFSr8hXiqfjDtifoHWxv_hSFhUExCZAZ7HAEJQ_iewejAVlT1CogGBIyBUbaPSBlNVqX0fMRr3wKqgRUMjcedjFQuyEXCfXeSEMTRirAJUKDLNHOHpDhBbIcR2D62mlibkrqB1B4zxCQBsGyjF0sX0M4IO_uG0is9AX1QQwZWSttxYLgqaryfDCZXiBi_Dl8_N_kzNXWkemQM17T67rS6uAyYDb5Gw-VLWHChP2GZTggBSgdkcmS87g8-f_f4FAvito8PUbAq-yRwidR6jcMZ6idy36-sQQoAo-MJ4m7pgegJu6qwlK75pIhe8uVvLNxvspXhNyHq1b8sxmv05iBdM0i8LgaQ29m3wky7PLPkeRPQiZD_Tac6rIHif0wZSPnh1NvJjCZfw_BIt7pjyvsfuzHSYnzvzWZf6-1h29I-6fg0fudWNNo2rQ2LhJqr6F-09I1a8e6fV5squkcJbJIhJzksZ_KOR9OonPcM4XOvSXRzdK6k-ezDj4e-IG8C_om2-vxOiDSvl2COu7jr6jUAM3CplPoyuVutQqgJ-XK2SOar2JFEsVfx-Zm4enYaX0oECRkAaColM7Lu172UINivleyDsh77TrWGfGmHkuObtUBK3yxEze2aJG5aMgXb8In4xVdX3iGox8zd46U2tgzom8WTiN_KAkB5Wyml12RH0qY7RoqEIPQwp9MLUK1I9GdQbnh8X4An2_qrFFq-MbtoxAUS9GAeEgWcKZD9noLCFzhv0PGMImJBCfB6x9jdI4PNb1B6WjSlnWGouoB5lMZnqT6XW2VjPczFfpOpsvFtntrNpki1zerter8laVmcpvF6sU16VaLfIi1yrPZ2YjU7lIs3Q-X2XZcpmUWBaLspgvUS-KldRikWKjTJ3EW-j8YWZC6HCTZ8v1elarPdYh_jaRktmBO3O5nfkNm9_su0MQi7Q2gcIEQIZq3DxM2o2NsmSKEH-HxMr9-LfJrPP1piJqA99k-STk08FQ1e2TwjVCPrGn4b-b1rvfsSAhn2LcQcinGPqfAQAA__8kah7p">