当前位置: 首页 > 知识库问答 >
问题:

用Clang交叉编译如何实现原生级优化?

计泉
2023-03-14

当使用clang-target选项进行交叉编译时,针对与本机系统相同的体系结构和硬件,我注意到 似乎比本机构建的计数器部分生成更差的优化

请考虑以下简单的代码示例:

int square(int num) {
    return num * num;
}

当使用-target x86_64-linux-elf-O3下进行优化时,本机 target代码生成生成:

square(int):
        mov     eax, edi
        imul    eax, edi
        ret

使用生成的代码x86_64产生:

square(int):
        push    rbp
        mov     rbp, rsp
        mov     eax, edi
        imul    eax, edi
        pop     rbp
        ret

< kbd >实例

尽管有相同的硬件和优化标志,但显然缺少了一些优化。如果将目标三元组中的none替换为linux,尽管没有使用特定于系统的功能,问题就会消失。

乍一看,它可能看起来根本没有优化,但不同的代码段显示它正在执行一些优化,只是不是全部。例如,循环展开仍在发生。

虽然上面的例子只是x86_64,但在实践中,这个问题会给基于 armv7 的受约束嵌入式系统生成代码膨胀,并且我注意到在某些情况下错过了一些优化,例如:

  • 不删除不必要的设置/清理说明(与 x86_64 中相同)
  • 不将某些顺序内联增量合并为单个添加指令(在 -OS 处,当内联类似矢量push_back 调用时。当从运行 armv7 的基于 arm 的系统本机构建时,这将进行优化。
  • 不将相邻的小整数值合并到单个 mov 中(例如在可选实现中将 32 位 intbool 合并。当从运行 armv7 的基于 arm 的系统本机构建时,这将进行优化。

我想知道我能做些什么,如果有的话,在交叉编译时实现与本机编译相同的优化?是否有任何相关标志可以帮助调整中隐含的调整

如果可能的话,我很想了解为什么交叉编译目标似乎无法优化某些东西,仅仅是因为系统不同,尽管有相同的架构和abi。我的理解是,LLVM的优化器在IR上运行,只要不依赖于目标系统本身,它就应该有效地生成相同的优化。


共有1个答案

郭皓
2023-03-14

太长别读:对于x86目标,当操作系统未知时,默认情况下会启用帧指针。您可以使用-fomit-frame-point er手动禁用它们。对于ARM平台,您当然需要提供更多信息,以便后端可以推断出目标ABI。使用-emit-llvm编译器以便检查Clang/LLVM的哪一部分生成低效代码。

应用程序二进制接口 (ABI) 可以从一个目标更改为另一个目标。C 语言中没有标准的 ABI。选择的取决于几个参数,包括架构、版本、供应商、操作系统、环境等。

使用 -target 参数可帮助编译器选择 ABI。问题是x86_64-none-elf不够完整,因此后端实际上可以生成快速代码。事实上,我认为这实际上不是一个有效的目标,因为在这种情况下,Clang发出了警告,并且错误的随机目标会出现相同的警告。令人惊讶的是,编译器仍然成功地使用提供的信息生成了一个通用二进制文件。像x86_64-windowsx86_64-linux这样的目标以及x86_64-unknown-windows-cygnus(Windows中的Cygwin)都可以工作。您可以在代码中获取 Clang 支持的平台、操作系统、环境等的列表。

ABI 的一个特定方面是调用约定。它们在操作系统之间是不同的。例如,x86-64 Linux平台使用System V AMD64 ABI的调用约定,而最近的x86-64 Windows平台使用基于较旧的Microsoft x64的vectorcall调用约定。对于旧的x86架构,情况更为复杂。有关此内容的更多信息,请阅读此内容和此处。

在您的情况下,如果没有操作系统的信息,编译器可能会选择自己的通用ABI,从而使用旧的推送/弹出指令。尽管如此,编译器假定edi包含传递给函数的参数,这意味着所选ABI是System V AMD64(或派生版本)。环境可以在堆栈优化中发挥重要作用,例如从函数外部访问堆栈(例如被调用函数)。

我最初的猜测是,由于缺少有关指定目标的信息,程序集后端禁用了一些优化,但x86-64 ELF的情况并非如此,因为选择了相同的后端。请注意,目标是由特定于架构的后端解析的(例如,请参见此处)。

事实上,这个问题来自Clang发出的红外代码,帧指针标志设置为all。您可以使用<code>-emit llvm</code>标志检查IR代码。您可以使用-fomit帧指针解决此问题。

在ARM上,问题可能有所不同,来自汇编后端。您当然应该指定目标操作系统或至少更多信息,如子架构类型(主要针对ARM)、供应商和环境。

总的来说,请注意,有理由认为,由于缺乏信息,更通用的目标会产生效率更低的代码。如果你想知道更多关于这个的信息,请在Clang或LLVM bug追踪器上填写一个问题,以便追踪发生这种情况的原因或/和让开发者修复这个问题。

相关帖子/链接:

  • CLANG:如何列出支持的目标架构?
  • https://clang.llvm.org/docs/CrossCompilation.html
 类似资料:
  • 我正在尝试为Android ARM交叉编译llvm/clang。 我也尝试了这里列出的所有步骤,以及在这里找到的指南,但没有运气。 任何帮助都将不胜感激。谢了! 编辑:现在我正在使用以下命令: 错误消息:CLANG36++:警告:编译过程中未使用参数:'-bundle'/users/paschalis/androide/toolchains/gcc/bin/../lib/gcc/arm-linux

  • 我正试图在Mac上交叉编译我的基于clang/LLVM的ELLCC交叉开发工具项目。我针对的是ARM/Linux。在构建FileCheck(或tbl-gen或在交叉编译-构建-工具步骤中构建的任何其他构建工具)时,构建失败,因为构建规则试图将- version-script选项传递给链接器。有很多配置魔术在进行,我似乎找不到说不要在Mac上使用-版本-脚本的咒语。 稍微澄清一下我的问题。ELLCC

  • 问题内容: 在Linux中,尤其是在Debian或Ubuntu上,有预打包的Mingw交叉编译器可以生成Windows EXE。 但是是否有使用Clang而不是GCC的类似交叉编译器?(或有关如何建造这种野兽的说明。) 问题答案: 我编写了一个工具,可以在Linux上使用clang轻松地为Windows进行编译。检出: https //github.com/tpoechtrager/wclang。

  • 交叉编译到Raspberry Pi的方法多种多样,也有交叉编译Qt或OpenCV的解决方案。 然而,我找不到任何解决方案来交叉编译一个与Qt也使用OpenCV的程序。 我指定了以前用于编译Qt的作为编译器: 我创建了目录,并在其中尝试: (下载的opencv源代码位于中,我最近使用Qt安装附带的G++编译器成功地为x64平台编译了opencv。)注意,是当前会话的用户名,以防其他初学者将来尝试这些

  • 问题内容: 我已经安装在Windows机器上的Go 1.2,写了一个虚拟的程序和设置环境变量,并以“AMD64”及“LINUX”。 当我发出“ ”命令时,出现错误: 这是什么意思? 问题答案: 它告诉您需要先构建所有工具,然后才能使用它们。 如果您的Windows GOARCH是amd64,则可以通过运行以下小批处理程序来“构建”所有必需的工具: 如果成功,那么您应该能够执行您所描述的操作(只使用

  • 问题内容: 我正在x86 ubuntu机器上为树莓派ARM目标编写一些代码。我正在使用gcc-linaro- armhf工具链。我能够交叉编译并在pi上运行一些独立程序。现在,我想将代码与外部库(例如ncurses)链接。我该如何实现。 我应该将程序与主机上现有的ncurses lib链接,然后在ARM上运行吗?(我认为这行不通)我是否需要为arm获取lib的源代码或预构建版本,将其放在我的lib