强制 64 位长双打?

Forcing 64-bit long doubles?

我正在建设 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。然而,即使我使用 -mfloat-abi=hard,这些仍然出现在图书馆档案中。据我所知,这是因为 ARM 64 位平台将 long double 定义为 128 位。

有什么办法可以改变这种行为吗?例如,我可以强制将 long double 定义为与 double 相同的大小吗?我知道 C 标准允许这样做,但我不确定是否有任何方法可以强制 Clang(我专门为此使用 Clang)使用这样的定义进行编译。

我以前不得不做类似的事情,在类型(特别是 longs)上胡乱摆弄。最好的办法是手动替换类型,因为这是获得所需内容的最简单、最直接的方法。您可以尝试使用宏或修改编译器,但根据我的经验,您创建的问题多于解决的问题,而且它通常是一个脆弱的解决方案,稍后会崩溃。

幸运的是,您正在使用的资源看起来维护得很好,并且您正在寻找的更改相当全面。你可以很简单地解决这个问题。假设您正在 运行 设置 Unix-like 系统,您可以 运行 从 musl 的基本目录中执行以下命令:

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

这个命令:

  1. 在所有文件中递归查找字符串 long double,并 returns 包含该字符串的文件名。
  2. 它被传递给 xargs,谁为每个文件名调用 sed 命令,并在其进行时打印。
  3. sed 运行s 时,它修改文件 in-place,并用 double.
  4. 替换 long double

当我尝试这个命令时,它 "just worked"。我会更仔细地仔细阅读差异以确保它正确地命中所有内容并且没有改变库的行为。

我最终找到了解决方案,但我不一定会推荐给所有人。它可能会在其他地方引发错误,但它足以满足我的需要。它还涉及从头开始构建 Clang(感谢@Art 的建议!)。此外,我正在处理的项目使用的是 LLVM/Clang 3.7.1,因此我对其他版本不做任何声明。


据我所知,AArch64 目标的 long double 定义出现在 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.
...

通过修改内部 2 行,我删除了对我在问题中提到的软 FP 例程的所有引用:

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

我的测试程序 -- SNU's version of the NASA Parallel Benchmarks -- 仍然可以正确验证,所以我假设我没有严重破坏任何东西。尽管如此,这仍然是一个重要的修改——我不建议大多数人使用它(它可能会导致其他地方损坏)。