最近项目组遇到编译安全固件,超出了r52安全核SRAM自带空间问题。急需要找寻方法优化代码体积(代码段大小+数据段大小+stack+bss段)方法,目前初步分析只有代码段&数据段有优化的可能,bss和stack优化空间并不大。有方法的小伙伴们可在下方留言,十分感谢。
本文尝试从Clang 自带优化选项,解读不同选项带来的优化效果。
LLVM项目
LLVM是一个开源的项目,是一个编译器框架,是一系列模块化、可重用的编译器以及工具链技术的集合。
LLVM的核心是LLVM库。同时LLVM还实现了一些周边工具。
LLVM的一个设计思想是优化可以渗透在整个编译流程中各个阶段,比如编译时、链接时、运行时等。
你可以基于LLVM提供的功能开发自己的模块,并集成在LLVM系统上,增加它的功能;或者利用LLVM来支撑底层实现,开发自己的工具。它可以很容易和IDE集成(因为IDE软件可以直接调用库来实现一些如静态检查这些功能),也很容易构建生成各种功能的工具(因为新的工具只需要调用需要的库就行)。
可见
https://github.com/llvm/llvm-project
https://llvm.org/docs/GettingStarted.html
LLVM最初代表Low Level Virtual Machine, 但是随着LLVM家族越庞大,这个最初的意思已经不适用。llvm.org 上的介绍很明确, LLVM就是这个项目的全称。
LLVM项目最初由UIUC的Vikram 和 Chris Lattner于2000年开始开发。他们的最初的目的是为了静态和动态编程语言开发一个动态编译技术。2005年,Chris进入苹果公司,继续进行LLVM的开发。2013年,索尼公司也开始使用Clang开发PS4。
在这之前,Apple公司一直使用gcc作为编译器,后来GCC对Objective-C的语言特性支持一直不够,Apple自己开发的GCC模块又很难得到GCC委员会的合并。等到Chris Lattner毕业时,Apple就把他招入靡下,去开发自己的编译器,所以LLVM最初受到了Apple的大力支持。
广义的LLVM是指整个LLVM架构,狭义的LLVM指的是LLVM后端(包含代码优化和目标代码生成)。
Clang
LLVM只是一个编译器框架,所以还需要一个前端来支撑整个系统,所以Apple研发了Clang,作为整个编译器的前端,Clang用来编译C、C++和Objective-C。可以用Clang/LLVM来和gcc做对比
Clang与LLVM的关系如图
相比于GCC,Clang具有如下优点
- 编译速度快:在某些平台上,Clang的编译速度显著的快过GCC(Debug模式下编译OC速度比GGC快3倍)
- 占用内存小:Clang生成的AST所占用的内存是GCC的五分之一左右
- 模块化设计:Clang采用基于库的模块化设计,易于 IDE 集成及其他用途的重用
- 诊断信息可读性强:在编译过程中,Clang 创建并保留了大量详细的元数据 (metadata),有利于调试和错误报告
- 设计清晰简单,容易理解,易于扩展增强
官方文档:
http://www.aosabook.org/en/llvm.html
https://llvm.org/docs/index.html
https://llvm.org/docs/GettingStarted.html
https://llvm.org/pubs/2008-10-04-ACAT-LLVM-Intro.pdf
https://llvm.org/docs/LangRef.html
https://github.com/llvm/llvm-project
编译优化
对于编译器来说, 优化是必须要经历的一个阶段, 经过优化的代码可以拥有更小的体积和更高效的执行。对于clang这个编译器前端而言。
现代编译器通常提供了许多优化选项,可以用来提高生成的代码的性能。这些优化包括函数内联、循环展开、死代码消除、常量折叠、指令重排等。
以下是一些常见的GCC和Clang的优化选项,代码的优化程度有一下的几个等级:
Code Generation Options¶
-O0, -O1, -O2, -O3, -Ofast, -Os, -Oz, -Og, -O, -O4¶
Specify which optimization level to use:
-O0 Means “no optimization”: this level compiles the fastest and generates the most debuggable code.
-O1 Somewhere between -O0 and -O2.
-O2 Moderate level of optimization which enables most optimizations.
-O3 Like -O2, except that it enables optimizations that take longer to perform or that may generate larger code (in an attempt to make the program run faster).
-Ofast Enables all the optimizations from -O3 along with other aggressive optimizations that may violate strict compliance with language standards.
-Os Like -O2 with extra optimizations to reduce code size.
-Oz Like -Os (and thus -O2), but reduces code size further.
-Og Like -O1. In future versions, this option might disable different optimizations in order to improve debuggability.
-O Equivalent to -O1.
-O4 and higher
Currently equivalent to -O3
https://clang.llvm.org/docs/CommandGuide/clang.html
https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
-O
-O1
优化。优化编译需要更多时间,并且对于大型函数需要更多的内存
使用 ,编译器会尝试减小代码大小和执行时间,而不执行任何需要大量编译时间的优化。-O
-O打开以下优化标志:
-fauto-inc-dec
-fbranch-count-reg
-fcombine-stack-adjustments
-fcompare-elim
-fcprop-registers
-fdce
-fdefer-pop
-fdelayed-branch
-fdse
-fforward-propagate
-fguess-branch-probability
-fif-conversion
-fif-conversion2
-finline-functions-called-once
-fipa-modref
-fipa-profile
-fipa-pure-const
-fipa-reference
-fipa-reference-addressable
-fmerge-constants
-fmove-loop-invariants
-fmove-loop-stores
-fomit-frame-pointer
-freorder-blocks
-fshrink-wrap
-fshrink-wrap-separate
-fsplit-wide-types
-fssa-backprop
-fssa-phiopt
-ftree-bit-ccp
-ftree-ccp
-ftree-ch
-ftree-coalesce-vars
-ftree-copy-prop
-ftree-dce
-ftree-dominator-opts
-ftree-dse
-ftree-forwprop
-ftree-fre
-ftree-phiprop
-ftree-pta
-ftree-scev-cprop
-ftree-sink
-ftree-slsr
-ftree-sra
-ftree-ter
-funit-at-a-time
-O2
进一步优化。GCC 执行几乎所有受支持的优化,这些优化不涉及空间速度权衡。
与之相比,此选项增加了编译时间和生成的代码的性能。-O
-O2打开 指定的所有优化标志。它还会打开以下优化标志:-O1
-falign-functions -falign-jumps
-falign-labels -falign-loops
-fcaller-saves
-fcode-hoisting
-fcrossjumping
-fcse-follow-jumps -fcse-skip-blocks
-fdelete-null-pointer-checks
-fdevirtualize -fdevirtualize-speculatively
-fexpensive-optimizations
-ffinite-loops
-fgcse -fgcse-lm
-fhoist-adjacent-loads
-finline-functions
-finline-small-functions
-findirect-inlining
-fipa-bit-cp -fipa-cp -fipa-icf
-fipa-ra -fipa-sra -fipa-vrp
-fisolate-erroneous-paths-dereference
-flra-remat
-foptimize-sibling-calls
-foptimize-strlen
-fpartial-inlining
-fpeephole2
-freorder-blocks-algorithm=stc
-freorder-blocks-and-partition -freorder-functions
-frerun-cse-after-loop
-fschedule-insns -fschedule-insns2
-fsched-interblock -fsched-spec
-fstore-merging
-fstrict-aliasing
-fthread-jumps
-ftree-builtin-call-dce
-ftree-loop-vectorize
-ftree-pre
-ftree-slp-vectorize
-ftree-switch-conversion -ftree-tail-merge
-ftree-vrp
-fvect-cost-model=very-cheap
-O3
优化更多。 打开 指定的所有优化,并打开以下优化标志:-O3-O2
-fgcse-after-reload
-fipa-cp-clone
-floop-interchange
-floop-unroll-and-jam
-fpeel-loops
-fpredictive-commoning
-fsplit-loops
-fsplit-paths
-ftree-loop-distribution
-ftree-partial-pre
-funswitch-loops
-fvect-cost-model=dynamic
-fversion-loops-for-strides
-O0
减少编译时间,使调试产生预期的结果。这是默认值。
-Os
针对大小进行优化。 启用除经常增加代码大小的优化之外的所有优化:-Os-O2
-falign-functions -falign-jumps
-falign-labels -falign-loops
-fprefetch-loop-arrays -freorder-blocks-algorithm=stc
它还使 能够使编译器针对代码大小而不是执行速度进行调整,并执行旨在减小代码大小的进一步优化。
-finline-functions
-Ofast
无视严格的标准合规性。 启用所有优化。它还支持并非对所有符合标准的程序都有效的优化
-Og
优化调试体验。 应该是标准编辑-编译-调试周期选择的优化级别,提供合理的优化级别,
同时保持快速编译和良好的调试体验。
这是比生成可调试代码更好的选择,
因为某些收集调试信息的编译器传递在 处被禁用。
-Og-O0-O0
与 一样,完全禁用许多优化传递,以便控制它们的单个选项不起作用。
否则启用所有优化标志,但可能干扰调试的标志除外:-O0-Og-Og-O1
-Oz
积极优化尺寸而不是速度。如果这些指令需要较少的字节进行编码,则可能会增加执行的指令数。
行为类似于包括启用大多数优化。
实测结果:-Oz 优化尺寸效果最优。