16

I'm building musl-libc statically for a project on an aarch64 (ARM 64-bit) platform. I'd like to avoid any soft floating point libraries such as GCC's soft float library routines. However, these are still appearing in the library archives even when I use -mfloat-abi=hard. As best I can tell, this is because ARM 64-bit platforms define a long double to be 128 bits.

Is there any way to change this behavior? For example, could I force long double to be defined as the same size as a double? I know this is allowed by the C standard, but I'm unsure if there's any way to force Clang (I'm specifically using Clang for this) to compile with such a definition.

Jesin
  • 1,009
  • 9
  • 12
tonysdg
  • 1,335
  • 11
  • 32
  • 1
    Try `-mlong-double-64`. Not sure if will work for ARM... – Eugene Sh. Feb 20 '18 at 16:13
  • @EugeneSh. Unfortunately returns a `clang-3.7: error: unknown argument: '-mlong-double-64'` error when I try to configure. I tried using `-Xclang` and `-mllvm` as well -- no dice. – tonysdg Feb 20 '18 at 16:20
  • what is available in a library archive has nothing to do with what actually is used included in the 'static' executable. – user3629249 Feb 20 '18 at 19:07
  • @user3629249: I'm not sure I understand what you mean -- when I compile `musl`, it produces `libc.a`, which contains `__extenddftf2`, a soft float library routine. I'm looking to avoid those routines. If "library archive" is the wrong term here, my apologies! – tonysdg Feb 20 '18 at 19:13
  • when a 'static' executable is created, the individual functions, that are actually used, are pulled from the library into the executable, The rest of the library is not used. – user3629249 Feb 21 '18 at 01:12
  • the library, being compiled as 'static' has nothing to do with which functions will be pulled from the library when some application is linked. If your actual objective is to reduce the library size, go to the source code for the library and edit it to remove those functions that you do not want to (ever) be linked in/executed. – user3629249 Feb 21 '18 at 01:15
  • @user3629249: I think I'm just explaining myself poorly here -- this isn't a matter of reducing the library size. I actually want to prevent `musl` from using 128-bit floating point math, which should eliminate the necessity for the soft float routines. They're getting pulled into the `musl` library because `vfprintf` requires handling a `long double`, which is currently defined as 128 bits long. If I can redefine `long double` as 64 bits, I think that will eliminate these routines (`__extenddftf2` specifically operates on quad precision floats, for example). – tonysdg Feb 21 '18 at 18:15
  • @tonysdg *They're getting pulled into the `musl` library because `vfprintf` requires handling a `long double`* `vfprintf` is dependent upon having `long double` processing in and of itself. I don't see how removing `long double` use from a third-party library changes that dependency. – Andrew Henle Feb 26 '18 at 16:37
  • 1
    @AndrewHenle: I'm assuming that the soft float library routines show up only because `long double` is defined as 128 bits (based on the `__extenddftf2` description and the fact that I know my `aarch64` platform has 64-bit FP registers). So while yes, `vfprintf` is dependent on `long double` processing, I guess what I'm wondering is if `long double` processing is in turn dependent on the soft float library routines. Does that make sense? – tonysdg Feb 26 '18 at 19:09
  • 1
    @AndrewHenle: Put another way, if `vfprintf` is dependent on `long double` processing, does the size of a `long double` change *what* that processing is? And if so, can I take advantage of that fact to force the size of a `long double` to fit in the hard floating point registers, instead of having to resort to using soft floating point? – tonysdg Feb 26 '18 at 19:10
  • In GCC you can use `-fsingle-precision-constant` but I think Clang lack support of it – Alejandro Blasco Feb 27 '18 at 08:39
  • 2
    This is horrible I know, but just to try your hypothesis, why don't you just perform a find-replace (replace "long double" with "double") in the whole lib? – Fusho Feb 28 '18 at 17:46
  • @oxuf: I've been seriously considering that, and if no other answers pop up after another week, that may be the approach I take. If I do, I'll post the results as a pseudo-answer. – tonysdg Feb 28 '18 at 19:00
  • What I did in a similar situation (was porting a system to sparc64 with 128 long doubles and didn't have time to dig up proper soft float libraries): build things, when the linker complains write down all the symbols it complains about and create functions for all the complaining symbols that all call `abort`. Horrible, but it moved things along until a time when we had time to waste on soft float. Changing the ABI (which is the result of what you want to do) is probably a bad idea and will probably blow something up when interfacing with code that uses the normal ABI. – Art Mar 05 '18 at 11:56
  • @Art: I wish it were that simple -- I can't dive into the details (due to space constraints), but I'm working on a research project that involves moving live applications between different ISAs. So we're used to messing with ABIs and blowing stuff up (figuratively speaking) :-) It's a niche question, and I was struggling to explain it without posting a blog-post-length question. But in the end, I was looking to see if there was a quick and dirty fix on the compiler side...looks like there isn't. Thanks for the feedback! – tonysdg Mar 05 '18 at 14:32
  • 1
    @tonysdg From what I remember (this was an eternity ago), this would require rebuilding the compiler. Maybe clang is different, but for gcc that was the only option. Although we did swear quite loudly that the architecture defined types and instructions that no CPU had (yet). Actually I recall now, our problem was two-fold. We needed to have those abort-stub functions after we rebuilt gcc to not generate the instructions that no CPU implemented and we didn't emulate in the kernel (like others did). – Art Mar 05 '18 at 14:58
  • 1
    @Art: Hmm, I hadn't considered rebuilding the compiler as an option -- it's heavy, sure, but we're already specially building it for our project. As much as that whole comment read "don't rebuild the compiler, it's way too much work", I think I might put some time into investigating that this afternoon haha. – tonysdg Mar 05 '18 at 15:08

2 Answers2

1

I ultimately found a solution, though I can't necessarily recommend it for everyone. It likely will induce bugs elsewhere, but it was good enough for what I needed. It also involves building Clang from scratch (thanks for the suggestion @Art!). Furthermore, the project I'm working on is using LLVM/Clang 3.7.1, so I make no claims for other versions.


As near as I can tell, the definition of a long double for the AArch64 target occurs in clang/lib/Basic/Targets.cpp:

...
MaxAtomicInlineWidth = 128;
MaxAtomicPromoteWidth = 128;

LongDoubleWidth = LongDoubleAlign = SuitableAlign = 128;
LongDoubleFormat = &llvm::APFloat::IEEEquad;

// {} in inline assembly are neon specifiers, not assembly variant
// specifiers.
...

By modifying the inner 2 lines, I removed any references to the soft-FP routines I mentioned in my question:

LongDoubleWidth = LongDoubleAlign = SuitableAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;

My test programs -- SNU's version of the NASA Parallel Benchmarks -- still validate correctly, so I'm assuming I didn't break anything too badly. Still, this is a non-trivial modification -- I don't recommend it for most individuals (it could lead to breakage elsewhere).

tonysdg
  • 1,335
  • 11
  • 32
  • I had a similar case: ppc32, gcc compiles long double operations into __gcc_qsub/qmult/etc calls. GCC can be compiled to work without quadmath, basically reducing long double to double. Clang does not support this, as of now. Changing it in the sources helped me! – LangerJan Feb 07 '19 at 21:50
0

I've had to do something similar before, fluffing around with types (particularly longs). Your best bet is to just manually replace the types by hand, as that's the simplest and most straightforward way to get what you want. You can try playing tricks with macros or massaging the compiler, but from my experience, you just create more problems than you solve, and it usually is a fragile solution that breaks later on.

Luckily, the sources you are working with look well maintained, and the changes you are looking for are rather blanket. You can knock this out quite simply. Assuming you are running a Unix-like system, you can run the following command from the base directory of musl:

$ grep -Rl 'long double' * | xargs -tn1 sed -i '' -e 's/long double/double/g'

This command:

  1. Looks for the string long double in all files, recursively, and returns the filenames which contain that string.
  2. Which gets passed into xargs, who invokes the sed command per each filename, printing as it goes along.
  3. When sed runs, it modifies the file in-place, and substitutes long double with double.

When I tried out this command, it "just worked". I would peruse the diff more carefully to make sure it hit everything proper and didn't alter the behavior of the library.