Keil MDK 编译器 AC5 和 AC6 优化选项重要内容和区别 ; N O6 `$ R5 g# Z7 P, O& L: V2 x, ]! \1 F% ]( J/ E 使用过Keil MDK (Arm Compiler 6)编译器V6版本的读者应该发现了一个问题,V6版本速度比V5版本编译速度快很多。) x0 K( T/ s( ]' S' c, ^ . T7 ]3 Z2 h$ J* W; Q7 j (说明:是V6版本编译器,不是V6版本MDK) {5 M8 z. u4 B) P/ i+ r * X+ o4 B& B! v n2 L 那你发现了Arm Compiler V6和V5有什么区别吗? 集成在MDK中的优化选项又有哪些区别? * M q, T% ^9 Y 一、关于Arm Compiler 6 $ }$ D, d" N- h ! @8 [& h r) M; m6 Q Arm Compiler 6(简称AC6)是用于Arm处理器的编译工具链,目前最新版本:Arm Compiler V6.14。4 `, A' i h9 x; B$ b 用于编译Coterx-M处理器的编译器很多,Arm Compiler就是其中一个,常用于Keil MDK、 Arm Development Studio(DS-5)中,还可用作独立工具链安装。 Arm Compiler 6工具链包括:4 ?. m/ q! o' i: D0 Z1 o0 [ armclang:基于LLVM和Clang技术的编译器和集成汇编器。8 O+ ^% v" ~, k& }( d ` armasm:armasm语法汇编代码的旧版汇编程序。将armclang集成汇编程序用于所有新的汇编文件。 armar:使ELF目标文件集可以一起收集。 armlink:将对象和库组合在一起以生成可执行文件的链接器。/ Z' K* R" H, m% M n7 T fromelf:镜像转换程序和反汇编程序。 Arm C libraries:嵌入式系统的运行时支持库。: I7 w _8 `% |3 m5 V Arm C ++libraries:基于LLVM libc++项目的库。 - R6 t- H v0 Y( @9 b, n 更多参考内容和地址:1 o2 V9 x9 _) s3 z 编译器Clang会代替GCC吗? 0 e$ D# |, ?- |6 A J$ c http://www2.keil.com/mdk5/compiler/6/. X8 w3 H" ]1 i) M https://developer.arm.com/tools-and-software/embedded/arm-compiler/downloads/version-6 m7 G- o# ^ ?1 F3 F) r 2 `& \4 |9 C, f4 Q 二、AC5和AC6& v8 u* K5 P- J" a* r( `" ?3 S Arm Compiler 5(AC5)算是用的比较多的一代编译器,在Keil MDK V4版本及V5早期的版本都是使用AC5。5 R( s8 l+ Z2 g3 ]- P 在2015年的时候,AC6发布了,并在随后新版本的MDK中集成了AC6,直到现在最新版本的MDK集成了AC6.13(可以修改版本):" |5 D @5 ^0 v; V5 A 9 Q" u6 _ l& x {$ a: W AC6相比之前版本的编译器做了很多改动,大家最为直观的感受就是编译速度提高了很多,还有代码大小。/ Y7 _" F5 O# f* d1 D$ L% n/ T " z8 O. O. o$ O. Z6 F4 g4 N4 Y 当然除了速度和大小,还有其他很多优势,比如:支持C ++ 14标准、使用TrustZone for Armv8-M为设备创建安全和非安全代码、兼容基于GCC创建的源代码,也就是GCC可以编译的源码它也能编译。, u: }2 B: |5 n 这是官方提供的代码大小对比: AC5和AC6是不同的编译器,兼容性方面还是有差异,需要迁移。这个迁移过程官方提供有文档:8 i# P9 N9 b+ k+ ?# N 7 N6 F; h( A, x; L https://developer.arm.com/docs/100068/0614/migrating-from-arm-compiler-5-to-arm-compiler-6 当然,也可以参看我之前分享的文章: \# w# W( h; G) r' f; M5 H9 E MDK-ARM编译器从V5升级到V6需要做哪些工作? . b* V& \7 C. R) z$ V 三、Keil MDK 优化选项0 r# h; g: m. q: A$ }9 l5 q 7 j0 \6 r# k" t, q W$ P ! M% Y7 k8 X$ {" |. C: L1 l4 _ 在Keil MDK中,相比AC5,使用AC6会增加几个优化选项:代码大小、速度、平衡等。 : i1 n `8 I! d8 T- l3 w, _: V7 N 优化选项包含:6 ]$ j0 j2 s2 t9 @2 o( {! D6 ], P $ l- i9 y' ]. D8 }% Z8 |2 h9 T6 [ / Y, e7 {2 _) p$ y& q -O0禁用所有优化。此优化级别是默认设置。使用-O0 结果可以加快编译和构建时间,但比其他优化级别生成的代码要慢。与-O0其他优化级别相比,代码大小和堆栈使用率明显更高 。生成的代码与源代码紧密相关,但是生成的代码量更大,包括无用的代码。 优化级别-O1 -O1在编译器中启用核心优化。此优化级别提供了良好的调试体验,并具有比-O0更好的代码质量,堆栈使用率也提高了。Arm建议使用此选项以获得良好的调试体验。& H" U" R) O6 b9 t! | 7 W! s. a# t: ^% _; L N -O1与-O0相比,使用时的区别是: 启用优化,这可能会降低调试信息的完整度。 9 h/ S! y# n% u 启用了内联和尾调用,这意味着回溯可能无法提供打开功能激活的堆栈。 8 A- {% O/ e9 C r% Z 不会调用没有使用,或没有预期调用的函数,代码量更小。 - D. Y3 Y" T2 F" b( \ 变量的值在不使用后可能在其范围内不可用。例如,它们的堆栈位置可能已被重用。。9 f \* R1 N6 P& |, j # v! x* }% w; q" U2 Y 优化级别-O2 -O2与-O1相比,有更高的性能优化。增加了一些新的优化,并更改了优化的启发式方法。这是编译器可能生成矢量指令的第一个优化级别。它还会降低调试体验。4 B8 m. X- T9 G1 n -O2与-O1相比使用时的差异是:) R J0 ]1 R' n9 u' g4 Q * ^. w0 u8 u- d/ W- N 编译器认为内联调用站点可获利的阈值可能会增加。9 c( T/ d: z+ i" K1 u+ F( _ & S6 A9 ^, L7 O1 p( q9 @ 执行的循环展开数量可能会增加。 $ `3 k5 M; e5 q7 l2 S+ |/ z# } 可以为简单循环和独立标量运算的相关序列生成矢量指令。 可以使用armclang命令行选项禁止创建矢量指令-fno-vectorize。 优化级别-O3 -O3与-O2相比,有更高的性能优化。此优化级别允许进行需要大量编译时分析和资源的优化,并且与-O2相比更改了优化的启发式方法。-O3指示编译器针对生成的代码的性能进行优化,而忽略生成的代码的大小,这可能会导致代码大小增加。8 ^5 S$ o; r( p! K8 Y -O3与-O2相比使用时的差异是: + S5 W( ^& S! c) X. W! E3 @ m 4 H6 Y; E6 I6 W; {" M/ i% q' V7 W- k 编译器认为内联调用站点是有利可图的阈值增加。 执行的循环展开量增加。 # J& c" D) n/ q : p% i+ a9 i2 z( W" `# E 在编译器管道中启用更积极的指令优化。 * I. `0 I9 C( k W 优化级别-Os! J. f: ?- c& p( U, b -Os目的是在不显着增加代码大小的情况下提供高性能。根据你的应用程序,提供的性能可能类似于 -O2或-O3。 - K, W+ o1 j4 W4 N) H -Os与-O3相比,可减少代码大小。但会降低调试体验。3 A$ Z" }% V- d5 u# E0 G7 H2 q2 t . t. k. S5 W5 A1 B6 J# m 6 a3 P6 d. u+ y' x! t -Os与-O3相比使用时的差异是:/ t/ Y4 t. G$ s+ B. K ! q8 n3 @! `1 j 降低编译器认为内联调用站点可获利的阈值。: _ W% F8 R. k. H3 }, I9 r# M # |, A/ J$ o5 l" z$ d- C: k# U0 p 显着降低了执行的循环展开量。" S* x( g2 V0 v/ F 优化级别-Oz% v5 h$ N7 q% W% \ -Oz目的是提供尽可能小的代码量。Arm 建议使用此选项以获得最佳代码大小。此优化级别会降低调试体验。 % u! @- L2 Z1 t) Q1 P -Oz与-Os相比使用时的差异是: , j- f2 W4 x2 T% T) |& t" | 编译器仅针对代码大小进行优化,而忽略性能优化,这可能会导致代码变慢。 未禁用功能内联。在某些情况下,内联可能会整体上减少代码大小,例如,如果一个函数仅被调用一次。仅当预期代码大小会减小时,才将内联启发式方法调整为内联式。6 Q$ J& }- [( i$ x" n1 L% K. y$ l: v " y9 k& x- V7 N! @; K* q( G1 ` $ J' i! A8 j, A3 r- ] 禁用可能会增加代码大小的优化,例如循环展开和循环矢量化。4 f4 e! W/ ~; ]& `1 E/ P0 S0 j+ X , ?8 j1 N7 U& V# d 循环是作为while循环而不是do-while循环生成的。- r* j, Q5 V& N& ~/ c0 G0 h- [ & X- t2 x7 u; M, T 优化级别-Ofast -Ofast从级别执行优化,包括使用 -ffast-math armclang选项执行的优化。4 C& ]' E4 r" [! D1 H # y* _% x" g; @0 S: g 该级别还执行其他进一步的优化,可能会违反严格遵守语言标准的要求。 2 A0 N" O: ]' [9 K( x- } 1 r+ D8 ~' [ f: n2 }( } 与-O3相比,该级别会降低调试体验,并可能导致代码大小增加。$ E) B* h& q0 e3 u % X1 T. }. N& m4 r# T' C 优化级别-Omax -Omax是最大程度的优化,并专门针对性能优化。它支持从级别进行的所有优化,以及链接时间优化(LTO)。5 U( W8 ^: U/ s* d$ W9 C y 在此优化级别上,Arm Compiler可能会违反严格遵守语言标准的规定。使用此优化级别可获得最快的性能。# l/ S6 n) h1 t. B. z ! w7 G( B% b' m, N4 A+ ^' y4 t0 V- a4 ? * N8 d1 c) ]' { 与-Ofast相比,该级别会降低调试体验,并可能导致代码大小增加。 - y$ X# Y* H( m7 g# t 如果你使用-Omax进行编译,并具有单独的编译和链接步骤,你还必须在armlink命令行中包括-Omax。 & J4 N+ _" d; u6 T/ E. P& j2 V+ s ; D- r/ d1 D% s/ I% C. q |