[fpc-devel] ARMHF a separate CPU? Why?

Vsevolod Alekseyev sevaa at sprynet.com
Sun Mar 9 18:09:32 CET 2014

I guess Free Pascal doesn't care for the same platforms that I do :) And
that would be the mobile ones - iOS, Android, Windows Phone, bada. Windows
Mobile is kind of comatose now, but still. Within this set, there's quite a
zoo of ABIs; almost none of those have a *single* ARM ABI. Do I need to
spell out that the mobile scene is kind of a Big Deal these days, and that
the installed base of Android alone dwarfs that of Raspberry Pi by orders of

> native compilation needs to "just work"

In case of said mobile platforms, making FPC work for those (espec.
WinPhone) was a fun challenge that will look great on my resume, but
definitely not something that "just worked". :)

> You can't really mix code where the c calling convention is different.

I don't think so. Since the FP ABI of a unit is known at compile time, the
compiler can be smart about it and generate argument translation thunks when
necessary. The key concept is the notion of "effective calling convention" -
that's the combination of the declared calling convention and the module's
FP ABI. For every function call that crosses the FP ABI boundary, the
compiler could generate a thunk and call that instead of the original

As for the thunks, there's nothing magical about those. I wrote some of them
manually during my porting efforts. Here's one for a hard-FP function that
takes two doubles and returns a double:

    fmdrr d0, r0, r1
    fmdrr d1, r2, r3
    stmfd sp!, {lr}
    blx MyFunc
    ldmfd sp!, {lr}
    fmrrd r0, r1, d0
    bx lr

Here's another, from another project, for a hard-FP function that takes a
single double argument and returns an int, written to be PIC compliant, and
switching mode into Thumb:

    fmdrr d0, r0, r1
    add r12, pc, #(MyFunc - MyFunc_ref - 7)
    bx r12

Naturally, the effective calling convention needs to be applied to function
pointer datatypes, too. When a pointer to a soft-FP function is being
assigned to a variable of a datatype that was declared in a hard-FP module,
it's a thunk address that needs to be assigned instead. Same goes for
scenarios with implicit function pointers - interface implementation,
virtual function overriding, etc.

This will break spectacularly in sketchy cases that involve casting function
pointers to void pointer or, worse yet, ints, and then back. But those are
sketchy anyway. Even GCC doesn't handle them right in all cases.

-----Original Message-----
From: fpc-devel-bounces at lists.freepascal.org
[mailto:fpc-devel-bounces at lists.freepascal.org] On Behalf Of peter green
Sent: Saturday, March 08, 2014 11:13 PM
To: FPC developers' list
Subject: Re: [fpc-devel] ARMHF a separate CPU? Why?

Vsevolod Alekseyev wrote:
> Does Free Pascal really treat ARMHF as a separate CPU target,
It didn't when I initally implemented it and from a quick look at the code
it doesn't now. What it does do is a little hacky but it followed the
pattern of what was already done and a cleaner soloution would have required
more radical changes.
>  distinct from regular ARM? May I ask why such design? In the grand
symphony of native code generation, the floating point calling convention
sounds, to me, as a much smaller detail than, for example, ARM vs Thumb or
PIC vs. non-PIC or floating point mode per se. 
Indeed from a code generation point of view those are probablly more
significant. On the other hand from a compatibility point of view they are
far less significant, you can mix code that uses arm with code that uses
thumb, you can mix PIC code with non-PIC code and you can mix code that uses
the FPU with code that does floating point in software with code that uses
the fpu (though IIRC fpc blocks the latter on arm eabi for no good reason).
You can't really mix code where the c calling convention is different.

You could in principle have a mode where the "cdecl" calling convention used
to interact with c libraries put floating point values in integer registers
while the calling conventions that are only used within pascal code used
floating point registers but I haven't seen anyone propose implementing
> Yet the latter features are mere options within the ARM target.
To understand the setup tets start from from a premise, namely that native
compilation needs to "just work", if I build or download a native compiler
for "platform x" I expect it to produce binaries that will work correctly
(though they may not be optimal) on "platform x" without the need to be
explicitly told how to do so at runtime.

Cross compiling is a different case, those doing crossbuilds generally
expect to have to do some manual configuration to get a working environment.

A freepascal compiler built for a given OS will target that OS by default
and each compiler only targets one CPU family. In most cases this just
works, for most CPUs and operating systems that freepascal cared about the
combination of OS and CPU locked down the ABI to one choice.

Unfortunately arm linux is an exception to this, there have been at least
four different ABIs targetted by freepascal for arm linux and all of them
have been used on systems that are more than capable of running native
compilers. The way this is handled is a bit hacky, each ABI has a #define
(FPC_OARM, FPC_ARMEL, FPC_ARMEB and FPC_ARMHF), when building the compiler
this #define it will set the default ABI and a few other things (default
linker script paths, default fpu). If none of the above defines are defined
and a native compiler is being built then the setting will be inherited from
the abi the compiler is being built for. 
If a crosscompiler is being built then the default is FPC_ARMEL.

I did not introduce this system, I merely expanded it to add armhf to the
supported variants.

At least in my original armhf patches you could override all the settings
that FPC_ARMHF implied (compared to the default FPC_ARMEL) manually with
enough command line flags, I don't know if that is still the case, nor do I
know if it is the case for other arm variants.

Florian later added code so that a compiler built for armhf and armv6 would
default to targetting armv6+vfpv2 rather than armv7-a+vfpv3_d16. 
This was done so that building and using the compiler on raspbian (and
similar raspberry pi targetted distros) would "just work".

fpc-devel maillist  -  fpc-devel at lists.freepascal.org

More information about the fpc-devel mailing list