4

我正在尝试整理一个嵌入式项目,其中开发人员选择将所有 h 和 c 文件包含到 ac 文件中,然后他们可以使用 -whole-program 选项仅编译一个文件以获得良好的大小优化。

我讨厌这一点,并决心把它变成一个传统的程序,只使用 LTO 来实现同样的效果。

开发工具包中包含的版本是;aps-gcc (GCC) 4.7.3 20130524 (Cortus) GNU ld (GNU Binutils) 2.22

一个 .o 文件 .text 是 0x1c7ac,分成 67 个 .o 文件 .text 出来为 0x2f73c,我添加了 LTO 内容并将其减少到 0x20a44,很好但还远远不够。

我已经尝试过 --gc-sections 并使用链接器插件选项,但他们没有进一步改进。

任何建议,我是否从 LTO 看到了正确的改进?

4

2 回答 2

0

在我看来,之前开发者选择的方法是正确的。该方法为编译器提供了最多的信息,从而为执行您想要的优化提供了最多的机会。这是一种糟糕的编译方式(任何更改都需要编译整个项目),因此将其标记为一个选项是个好主意。

当然,您必须针对这样的构建运行所有集成测试,但这应该是微不足道的。除了编译时间(这不应该是一个问题,因为您不需要一直以这种方式构建......仅用于集成测试)之外,所选方法的缺点是什么。

于 2015-10-15T23:39:05.473 回答
0

要使 LTO 完美工作,您需要在链接阶段提供与编译阶段相同的信息和优化算法。GNU 工具无法做到这一点,我相信这实际上是创建 LLVM/Clang 的激励因素之一。

如果您想详细检查差异,我建议您为每个选项生成一个 Map 文件(ldoption -Map <filename>),并查看是否有未内联的函数或更大的函数。extern inline您可以通过将函数的定义移动到头文件中并将其定义为有效地将其转换为宏(这是 GNU 扩展)来强制这些函数内联来手动解决内联的缺失。

较大的函数可能不会受到持续传播的影响,我认为您对此无能为力。您可以通过仔细声明函数属性来进行一些改进,例如const, leaf, noreturn,purereturns_nonnull. 这些有效地保证了函数将以特定方式运行,如果编译器使用单个编译单元,编译器可能会检测到这种方式,并且允许额外的优化。

相比之下,Clang 可以将您的目标代码编译为一种特殊类型的字节码(LLVM 代表低级虚拟机,就像 JVM 是 Java 虚拟机,并运行字节码)然后可以在链接时执行此字节码的优化(或者实际上运行时,这很酷)。因为无论你是否使用 LTO,这个字节码都会被优化,并且优化算法在编译器和链接器之间是通用的,理论上无论你是否使用 LTO,Clang/LLVM 都应该给出完全相同的结果。

不幸的是,现在 C 后端已从 LLVM 中删除,我不知道有任何方法可以将 LLVM LTO 功能用于您所针对的自定义 CPU。

于 2015-10-15T23:15:58.267 回答