[llvm-dev] [RFC] Introducing an explicit calling convention

Chris Lattner via llvm-dev
Fri, 18 Jan 2019 06:29:35 -0000

On Jan 16, 2019, at 1:33 AM, David Chisnall via llvm-dev <llvm-dev at
lists.llvm.org> wrote:
> On 15/01/2019 21:56, Manuel Jacob via llvm-dev wrote:
>> Sometimes people complain that ABI handling in the frontend is hard and
that they have to duplicate (in their language’s frontend) what Clang does.
However, I don’t think that pushing more of this complexity into LLVM would be a
good idea.  What I suggest is that there should be a helper library for ABI
lowering (ideally that library should be used by Clang eventually).  What do you
think?
>
> I would love to see this and I was hoping that some of the Swift work would
lead to a refactored clang library that allowed you to generate IR corresponding
to C/C++ functions.
>
> I think we have four use cases for front ends:
>
> 1. JIT'd language, minimal FFI.  This doesn't care what the calling
convention is, doesn't care that it's stable, does care that it's
efficient.  Except at well-defined external calls, is very happy for LLVM to
pick a different calling convention for every function.
>
> 2. Language that has only an LLVM implementation, but does support static
compilation and linking across different compiler versions. Doesn't care
what the calling convention is, but it has to be stable. LLVM is free to pick a
different calling convention for every type signature, but the convention must
be stable and doesn't have to match the platform ABI.
>
> 3. Language that is adding a new LLVM implementation that is expected to
interoperate with an existing implementation.  There are a lot of these out
there and they all end up suffering.  Typically they either fork LLVM and add a
custom calling convention, or they try to upstream a calling convention.  When
they want to support a new architecture, then need to coordinate their releases
with LLVM to get their calling conventions supported by the new back end.  They
make live even harder for the next person to want to use their calling
convention by adding more undocumented informal contracts between how the front
end generates LLVM IR and how the back end maps this to register / stack layout.
>
> 4. Language that wants to interoperate with C/C++.  These sometimes embed a
big chunk of clang.  This probably should be the preferred solution, because it
will invariably miss corner cases (packed structs, for example) if it does
anything simpler.  Unfortunately, clang isn't really designed for this kind
of embedding and the APIs that consumers need change quite frequently.
Alternatively, they implement their own partial ABI support.  For the core C ABI
(ignoring GNU extensions and C++), it is *much* easier to do this in a JIT that
generates assembly directly than one that targets LLVM IR.  ABI specs describe a
fairly simple (even amd64, though that's stretching it somewhat) set of
rules for mapping C constructs to registers / stack offsets.  These are well
defined and well documented.  The corresponding set of mappings from C
constructs to IR constructs are undocumented outside of the code and the only
way that you can reliably find them is to run clang and see what it emits (I
have done this - it's not fun).  If you need only basic C interop, doing
this for each platform that you support ought to be simpler than embedding
clang, but it isn't.
>
> Ideally, we'd have both a clean set of APIs for other front ends to
embed clang (including a lot of what libclang exposes: parsing C headers,
walking types, and then generating interoperable code), built on top of a clean
way for the front end to either specify the exact ABI requirements or leave them
entirely up to later optimisations or the back end.

If anyone would like to organize a round table at EuroLLVM to talk about this
topic, I’d love to participate.  I have lots of thoughts and opinions here (but
can’t really explain it all without a whiteboard) and they may be interesting to
discuss.

-Chris