强制使用64位长双精度浮点数?

16
我正在为一个基于 aarch64(ARM 64位)平台的项目静态构建 musl-libc。我想避免使用任何软浮点库,例如 GCC 的软浮点库例程。然而,即使我使用 -mfloat-abi=hard,这些库档案仍会出现。根据我所知,这是因为 ARM 64 位平台将 long double 定义为 128 位。
有没有办法改变这种行为?例如,我是否可以强制定义 long doubledouble 的大小相同?我知道这在 C 标准中是允许的,但我不确定是否有办法强制 Clang(我特别在使用 Clang 进行此操作)以这种定义进行编译。

1
@AndrewHenle:我假设软浮点库例程只会出现,因为long double被定义为128位(基于__extenddftf2的描述和我知道我的aarch64平台有64位FP寄存器的事实)。所以虽然是的,vfprintf依赖于long double处理,但我想知道的是,long double处理是否反过来依赖于软浮点库例程。这有意义吗? - tonysdg
1
换句话说,如果vfprintf依赖于long double处理,那么long double的大小是否会改变该处理的内容?如果是这样,我是否可以利用这个事实来强制long double的大小适应硬浮点寄存器,而不必诉诸使用软浮点? - tonysdg
2
这很糟糕,我知道,但是为了验证你的假设,为什么不在整个库中执行查找替换(将“long double”替换为“double”)? - Fusho
1
@tonysdg 从我记得的(那是一个遥远的年代),这将需要重新构建编译器。也许clang不同,但对于gcc而言,那是唯一的选择。虽然我们的确大声发誓,这个架构定义了CPU尚未拥有的类型和指令。实际上,我现在回想起来了,我们的问题是双重的。我们需要在重新构建gcc之后有这些中止存根函数,以避免生成CPU未实现并且我们未在内核中模拟的指令(像其他人一样)。 - Art
1
@Art:嗯,我没有考虑重新构建编译器作为一个选项——它很重,当然,但我们已经为我们的项目特别构建了它。尽管整个评论都说“不要重新构建编译器,这太费力了”,但我想我可能会花点时间在今天下午调查一下哈哈。 - tonysdg
显示剩余12条评论
2个回答

1

最终我找到了一个解决方案,但我不能保证它适用于所有人。这可能会在其他地方引起错误,但对于我所需的内容已经足够好了。它还涉及从头开始构建Clang(感谢@Art的建议!)。此外,我正在使用LLVM/Clang 3.7.1进行项目开发,因此我不对其他版本做出任何声明。


据我所知,AArch64目标的长双精度类型定义在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.
...

通过修改内部两行,我删除了我在问题中提到的任何关于软浮点例程的引用。
LongDoubleWidth = LongDoubleAlign = SuitableAlign = 64;
LongDoubleFormat = &llvm::APFloat::IEEEdouble;

我的测试程序-- SNU的NASA并行基准测试版本 -- 仍然正确验证,因此我认为我没有太糟糕地破坏任何东西。不过,这是一个非常重要的修改--我不建议大多数人使用它(它可能会导致其他地方的故障)。


我有一个类似的情况:ppc32,gcc将长双精度操作编译为__gcc_qsub / qmult /等调用。 GCC可以编译为在没有quadmath的情况下工作,基本上将长双精度减少到双精度。 Clang目前不支持此功能。 在源代码中更改它对我有所帮助! - LangerJan

0

我以前也遇到过类似的问题,需要处理类型(特别是long)。最好的方法就是手动替换类型,因为这是最简单和直接的方法来获得你想要的结果。你可以尝试使用宏或调整编译器的技巧,但从我的经验来看,这只会制造更多问题,而且通常是一个脆弱的解决方案,后来会出现问题。

幸运的是,你正在处理的源代码看起来维护得很好,你要做的更改相当普遍。你可以很简单地完成这个任务。假设你正在运行一个类Unix系统,你可以从musl的基本目录运行以下命令:

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

这个命令:

  1. 递归查找所有文件中的字符串long double并返回包含该字符串的文件名。
  2. 将结果传递给xargs,它会针对每个文件名调用sed命令,并在替换的同时打印输出。
  3. sed运行时,直接修改文件内容,将long double替换为double

当我尝试运行此命令时,它“只是工作了”。我会更仔细地查看差异,确保它正确地覆盖了所有目标,并没有改变库的行为。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接