ARM procedure calls (sorry)

Hi again,

I forgot to remove the ‘important notice’ stuff from the footer of my last email, so I am sorry.

Here’s my previous question:

I’m looking to allow LLVM to simplify more library calls and it appears that currently this cannot happen for functions that are declared with a call standard other than C. Specifically I’m trying to work around function calls annotated with ‘aapcs_vfpcc’.

I see that the VFP standard is used when -mfloat-abi=hard is provided, but it is not used when arm-none-eabihf is used as a triple. It looks like this happens because Clang decides that the ARM backend will be capable of figuring out what standard to use and so doesn’t worry about using extra annotations. But the backend is also capable of querying the Float ABI too, so I assume it would be capable of calculating the standard in either case. I want to make a simple change to Clang like this:

/// Return the default calling convention that LLVM will use.
llvm::CallingConv::ID ARMABIInfo::getLLVMDefaultCC() const {
// The default calling convention that LLVM will infer.
if (isEABIHF() || getTarget().getTriple().isWatchABI() ||

  • Kind == ARMABIInfo::AAPCS_VFP)

return llvm::CallingConv::ARM_AAPCS_VFP;

But this change makes the CodeGen tests, that are testing the declared aapcs, fail. So my question is, (1) why is does the behaviour differ between -mfloat=hard and eabihf targets and (2) what would definitely break if clang didn’t annotate some functions with aapcs_vfp?

cheers,
sam

(1) why is does the behaviour differ between -mfloat=hard and eabihf targets

Hi Sam,

This looks like an oversight. It should mark functions as vfp on eabihf.

I haven't seen that triple been used yet, so maybe that's the reason
why it's not recognised.

We don't do "if Env.endsWith("hf") HardFloat = true;" as that could
have false-positives, so we do one at a time.

(2) what would definitely break if clang didn't annotate some functions with aapcs_vfp?

Many assumptions would break down. The vfp flag was created because it
is possible to have IR with more than one PCS (attributes, merged
modules, etc), so each function has independent behaviour.

Also, front-ends can, for whatever reason, create separate pools of
soft-float and hard-float functions, if it can guarantee they're
disjoint. For example, if user code is allowed to have hard-float but
library code is not, so you create thunks to convert the calling
convention back and forth, as a way to migrate separate parts of your
toolchain.

If we remove the attribute from the function, we'd go back relying on
the triple, which is not just unreliable, but can't convey all the
information that we need in object files.

I think the real question is: why is your pass only valid in the C
calling convention?

cheers,
--renato

(1) why is does the behaviour differ between -mfloat=hard and eabihf targets

There are three separate components to determine this part of the ABI:

1. The triple
2. Explicit CC attribute overrides.
3. Some weird "-float-abi" backend option.

Clang's current policy is to emit Modules that work with either
-float-abi=default or the explicitly specified float-abi: the checks
are basically, "if -float-abi is changing something implicitly, mark
that in the IR with CC attrs too".

As Renato says, I think this is necessary for things like LTO to work
(where the final link step runs under -float-abi=default I think).

I'm looking to allow LLVM to simplify more library calls and it appears that currently this cannot happen for functions that are declared with a call standard other than C.

This is a really tricky one. My first intuition is that in an
"arm-none-eabi -mfloat-abi=hard" environment, you'd expect the C & C++
standard libraries to be soft-float (otherwise isn't it really
arm-none-eabihf?). We get this wrong now: "float foo(float *in) {
return floorf(*in); }" uses hard-float.

But even if that's true, how does Clang know what's standard library
and what's not (e.g. POSIXy stuff might count)? And should it be in
the business of silently modifying declarations like that if it did?
You could argue that a library intending to be compatible with both
-mfloat-abi=hard and the default should annotate its functions with
__attribute__((pcs("aapcs"))). But you could also argue that's a
ridiculously onerous burden to put on library writers.

I've got no good answers to any of those issues yet.

However, to the extent that AAPCS, AAPCS_VFP and C are compatible
under the given triple (careful, they're not on iOS), I think LLVM IR
probably allows them to be intermixed. So you could probably
legitimately optimize integer/pointer libcalls even with the
mismatching CC.

Tim.

Tim, Renato

Thanks to you both, I will go back to LLVM and see how I get on allowing SimplifyLibCalls to operate on aapcs calls. On a related note, are there any plans to enable Clang to use the backends for target information? There seems to be a lot of mess and duplication which is bound to cause issues at some point.

Thanks again,

sam

Sam Parker

Software Engineer, Compilation Tools

Development Solutions Group

Exposing the raw target information would be dangerous, most of the
target info in Clang is derived from the Triple and compiler flags.

What do you have in mind?

--renato

Well the code I was looking at was making assumptions about what the backend will decide about procedure calls, so why not ask the backend? I haven’t looked at the target classes in Clang in a long time, but just having a quick look now there still appears to be duplication with LLVM’s target machine and subtargets, at least for ARM anyway. For instance, the triple is used for ABI and data layout calculations and there’s no end of flags for features. I guess I must be missing something, but it just seems odd and harder to maintain having two descriptions of the targets.

cheers,

sam

Sam Parker

Software Engineer, Compilation Tools

Development Solutions Group

Well the code I was looking at was making assumptions about what the backend
will decide about procedure calls, so why not ask the backend?

Exposing back-end information to the front-end is a pandora's box. You
can start naive and only ask what you really need to know, and then
people will be using for all sorts of little quirks and suddenly the
IR generated by Clang will be in a tight contract with what each LLVM
back-end can consume (aka. high coupling).

The way we do today, for better or worse, is to have the Triple class
expose all information front-ends need to know. This is far from
perfect, but if you want to make that relationship more coese, I
suggest you look into the Triple class.

One of the recent efforts by Daniel Sanders to re-factor the Triple
class was a way to fix that madness in the Mips back-end, which is
somewhat similar to ARM's. If you want to look into that, I suggest
you contact Daniel and Eric (CC's), as there was a lot of discussions
around design and behaviour.

I haven't looked at the target classes in Clang in a long time, but just having a
quick look now there still appears to be duplication with LLVM's target
machine and subtargets, at least for ARM anyway.

Most of the target knowledge in Clang uses the Triple already, and
they're mostly concerning themselves with front-end stuff, which is
what we want. The meaning of triples and flags play a different part
in all this...

For instance, the triple is
used for ABI and data layout calculations and there's no end of flags for
features. I guess I must be missing something, but it just seems odd and
harder to maintain having two descriptions of the targets.

This is, unfortunately, a *requirement*. And a bad one at that.

In the GNU world, the triple is mostly descriptive, and the build-time
configure options are what really define behaviour. So each
distribution (of Linux, Mac, BSD) has done their own ways. Most of the
time, they have also chosen their own "different" triples, but not
always.

In the LLVM world, we don't have build-time options, so *all* logic
has to be in triples and command line options. Most of the time that
works because the triples are all slightly different, but they're not
always, and sometimes we either get things wrong, or we can't
represent something that GCC can with build-time options.

Using target options won't help, since the target class doesn't know
which system it's running and which ABI is should default to or fall
back to, etc. So, if we keep all that logic in the Triple, which is an
LLVM class and *has* access to the target information, we *can*
perform a proxy pattern from the real target information to the
front-ends without perverting the encapsulation.

Maybe, the simplest way to fix this mess is to enhance the Triple
class to have more target knowledge, so we can make sure that whatever
Clang interprets as "arm-none-eabi" is the exact same thing the
back-end will when it sees it in the IR.

We're probably pretty close, even it mostly by accident. However,
making it clearer won't be a bad move.

cheers,
--renato

From: cfe-dev [mailto:cfe-dev-bounces@lists.llvm.org] On Behalf Of Renato
Golin via cfe-dev
Sent: 22 August 2016 13:55
To: Sam Parker
Cc: Daniel Sanders; nd; cfe-dev@lists.llvm.org
Subject: Re: [cfe-dev] ARM procedure calls (sorry)

> Well the code I was looking at was making assumptions about what the
> backend will decide about procedure calls, so why not ask the backend?

Exposing back-end information to the front-end is a pandora's box. You can
start naive and only ask what you really need to know, and then people will
be using for all sorts of little quirks and suddenly the IR generated by Clang
will be in a tight contract with what each LLVM back-end can consume (aka.
high coupling).

The way we do today, for better or worse, is to have the Triple class expose
all information front-ends need to know. This is far from perfect, but if you
want to make that relationship more coese, I suggest you look into the Triple
class.

One of the recent efforts by Daniel Sanders to re-factor the Triple class was a
way to fix that madness in the Mips back-end, which is somewhat similar to
ARM's. If you want to look into that, I suggest you contact Daniel and Eric
(CC's), as there was a lot of discussions around design and behaviour.

Yes, Daniel developed a series of patches that brought the Mips backend into
line with some of the other targets by modifying the triple for Mips to carry
ABI information. (I will taking over that patch series).

Our goal there was to be able to distinguish at the relevant places what ABI
was in use, as certain targets have the same triple but different ABI.

I've forwarded this message onto Daniel as he is no longer with Imagination
Technologies.

Thanks,
Simon

Yes, Daniel developed a series of patches that brought the Mips backend into
line with some of the other targets by modifying the triple for Mips to carry
ABI information. (I will taking over that patch series).

Hi Simon,

Thanks! Maybe then it's better if Sam talks to you directly. :slight_smile:

Our goal there was to be able to distinguish at the relevant places what ABI
was in use, as certain targets have the same triple but different ABI.

Seems to be what Sam is referring to, so probably a common problem to be solved.

cheers,
--renato

It comes down to how to propagate information through the backend for ABI information. I’ve also not had time to review the patches - since it involves making sure that my original idea isn’t feasible.

-eric

From Simon’s email:

I’ve forwarded this message onto Daniel as he is no longer with Imagination

Technologies.

Thanks.

From Renato’s email:

In the GNU world, the triple is mostly descriptive, and the build-time
configure options are what really define behaviour. So each
distribution (of Linux, Mac, BSD) has done their own ways. Most of the
time, they have also chosen their own “different” triples, but not
always.

In the LLVM world, we don’t have build-time options, so all logic
has to be in triples and command line options. Most of the time that
works because the triples are all slightly different, but they’re not
always, and sometimes we either get things wrong, or we can’t
represent something that GCC can with build-time options.

The new Debian mips64el port hit this problem recently and is currently carrying a small patch to change a default for their triple. I was planning to suggest something that would bring such patches upstream but I decided to wait until my latest set of triple patches were upstream before adding another element to an already complicated problem.

The gist of that plan is to attach such distribution specific behaviour to vendored triples and allow distributions to map their distribution triple to their preferred vendored triple in LLVM. The overall effect is that distributions get the ability to control the defaults of their native compilers like they do for gcc but LLVM’s ability to cross-compile to anything is preserved.