[LLVMdev] Hash Table Virtual Calls with Conflict Resolution Stubs

Stephen Cross scross at scross.co.uk
Tue Jun 2 16:04:51 PDT 2015


Hello,

So I've done a bit of digging in GCC and for the static chain pointer
it seems to be
using [1]:

* x86: ecx
* x86_64: r10
* ARM: ip (r12)
* AArch64: x18
* PowerPC: r11

The choices here are notable: on ARM, GCC uses ip (r12), the
'intra-procedure-call
scratch register', which can technically be used by veneers generated
by the linker,
but the nature of nested functions means this doesn't occur; I believe it also
works for my use case.

On AArch64, GCC uses x18, the 'platform register', which appears to be unused by
Linux and therefore available as a scratch register. However it *is*
used by iOS [2]
and GCC appears to not have chosen a static chain register for iOS
AArch64 yet [3].
I'm raising this issue on the GCC mailing list.

Currently LLVM supports x86 (ecx) and x86_64 (r10), but as far as I can tell the
other backends don't support 'nest' and hence treat the parameter as
if it didn't
have the attribute; it looks like the PowerPC backend supports the trampoline
intrinsics but its nested parameter isn't passed in the same way as
GCC (though I
haven't yet investigated this target in detail).

I'm putting together patches for ARM and AArch64 that implement 'nest' in their
respective backends to match the choices made by GCC and writing tests
to verify the
registers used are correct (btw LLVM has a great test system). On the
backends that
don't support 'nest' I'd suggest that they should report an error (or
at least some
form of notice) since they're not using an out-of-band mechanism, and
I'd be happy
to write tests to check this. I would also be interested in making the
documentation
for 'nest' slightly clearer. Does this sound sensible?

As for renaming/generalising 'nest', I'm going to leave this for now
but probably
raise it a later time. I do think it'd be cleaner to have something
like 'outofband'
that supports arbitrary parameter types, so e.g. the Loci frontend
doesn't have to
generate different IR for each target (32-bit targets will pass a
pointer to a i64
value, whereas 64-bit targets pass the value directly). This would
replace 'nest'
but have identical behaviour (and register selection) for the case where the
parameter is a pointer.

> Have you looked at how Objective-C implements this?  There are at least four Objective-C runtimes that are open source, which all solve this problem in slightly different ways.  The GCC, GNUstep, Apple Legacy, Apple Modern, and ObjFW runtimes are all supported by clang, so you can take a look at the IR generation easily as well.

I haven't looked at Objective-C. As far as I can tell, Objective-C
doesn't face the
same problem as shown here because blocks essentially pass their scope
as a normal
pointer argument (I ran an Objective-C program through Clang to check
this). Calls
to protocol methods appear to use objc_msg_lookup and then just
directly call the
returned function pointer.

Does that sound correct? (Or did I miss the point you were making?)

Kind regards,
Stephen

[1] https://github.com/gcc-mirror/gcc/blob/7c62dfbbcd3699efcbbadc9fb3aa14f23a123add/gcc/testsuite/gcc.dg/cwsc1.c
[2] https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html
[3] https://github.com/gcc-mirror/gcc/blob/7c62dfbbcd3699efcbbadc9fb3aa14f23a123add/libffi/src/aarch64/ffitarget.h#L66

(GCC links are to specific commits so they don't go out-of-date.)




More information about the llvm-dev mailing list