Using MacOS calling convention to call external functions


I do have an MLIR use case, but figured this should be discussed as part of code generation, since my issue is related to that. So the use case is the following: I do have a library compiled using Apple clang 14.0.0, in which functions expect arguments to be passed into register x0 and the stack. Then I do have my own compiler built on top of LLVM/MLIR that do some code generation, including calls to functions from my library. Now the thing is that this generated call is using a different calling convention, passing the 8 first arguments into register x0..x7, and the remaining ones into the stack, which is different from what the library’s functions would expect. Now I think I’m using the right triple for the target machine (aarch64, apple, darwin) in LLVM while adding the pass to emit the object file.

So I’m wondering if using MacOS calling convention isn’t supported at all, in which case I would wonder how to go with such use case? Or that I’m just missing something to enable a different calling convention?

I worked on something in this area a while back: ⚙ D104123 [llvm][AArch64] Handle arrays of struct properly (from IR)

What I remember is that at least for Linux, the 4 parameters in registers was enforced by Clang then the llvm backend did the rest. When Clang wasn’t involved you could get up to 8 in registers.

The bug in question was an IR generating framework that did not go through Clang, much like your example. So the fix was mainly to not crash on valid IR, the output is not ABI compliant when only llvm is involved.

I can’t say I agree with the ABI enforcement being split like that, but that’s how it is.

How you would work around that from MLIR I don’t know. I guess the simple (but tiresome) way would be to duplicate Clang’s ABI enforcement in your compiler.

Specifically my comment in the test file:

;; Some of these examples are not ABI compliant and they're not
;; meant to be. For instance according to the ABI an aggregate
;; with more than 4 members must go in memory. This restriction
;; is applied earlier in the compilation process so here we do
;; see 8 member types in registers.

Thanks for your explanation. So I understand that it’s possible to generate such code, only if I can enforce that before codegen. I will then jump into another MLIR discussion to see how I can do that with the framework.

From the other discussion in MLIR

I was doing something wrong in my compiler, so this issue doesn’t apply anymore, the codegen is using appropriate calling convention to call my external function