我一直在阅读一些汇编编程视频,以便更好地理解如何手动优化编译后留下的*.s文件.gcc/g++ -S ... 其中一个主题是重构冗余代码,演示如何将冗余代码移动到自己的标记块以ret结束并用呼叫替换它.
视频中给出的示例是2个块,包含:
mov eax,power
mul ebx
mov power,eax
inc count
Run Code Online (Sandbox Code Playgroud)
它取而代之的是call CalculateNextPower和CalculateNextPower看起来像:
CalculateNextPower:
mov eax,power
mul ebx
mov power,eax
inc count
ret
Run Code Online (Sandbox Code Playgroud)
出于好奇,试图减少编译大小,我用-S和各种优化编译了一些C和C++项目,包括-Os,-O2,-O3,-pipe,-combine和-fwhole-program,并分析了结果*.s使用轻微修补(for .s文件)版本的duplo进行冗余的文件.只有-fwhole-program (现已弃用的IIRC)对消除文件中的重复代码有显着影响(我认为它的替换(-s)-flto在链接时会表现相似 - 大致相当于用-ffunction-sections -fdata-sections编译和--gc-sections链接)但仍然错过了大量的代码块.
使用duplo输出的手动优化导致随机C项目的大小减少约10%,并且当仅具有至少5个连续重复指令的连续块组件被重复数据删除时,随机C++项目中几乎减少30%.
我是否遗漏了一个编译器选项(甚至是一个独立的工具),在编译大小时会自动消除冗余程序集(包括其他编译器:clang,icc等等) 或者是否缺少此功能(原因?)?
如果它不存在,则可以修改duplo以忽略以'.'开头的行.要么 ';' (以及其他人?)并使用重复代码调用函数替换重复的代码块,但我对其他可直接使用编译器内部表示(最好是clang或gcc)的建议持开放态度.
编辑:我修补杜普洛识别重复组装块在这里,但它仍然需要在此刻手动重构.只要使用相同的编译器生成代码,就可以(但可能很慢)识别最大的重复代码块,将它们放在自己的"函数"块中,并用CALL替换代码到该块.