4.2.优化级别¶
编译器可以执行多种优化以提高执行速度并缩减 C 和 C++ 程序的大小。表 4.2 列出了可用的优化级别、每个级别的范围以及在每个级别执行的一些优化示例。
优化级别 | 范围 | 执行的优化 |
---|---|---|
--opt_level=off ,-Ooff |
无 | 无。这是 C28x 编译器的默认设置。 |
--opt_level=0 ,-O0 |
语句 | |
--opt_level=1 ,-O1 |
块 |
|
--opt_level=2 ,-O2 |
功能 | |
--opt_level=3 ,-O3 |
文件(即文件中的跨函数) |
|
--opt_level=4 ,-O4 |
编程 | 链接时优化。请参阅 TMS320C28x 优化 C/C++ 编译器用户指南中的第 3.6 节“链接时优化(–opt_level=4 选项)”。 |
注释
为了生成高效的代码,强烈建议将优化级别设置为 -O2
或更高。
有关这些优化的说明,请参阅 TMS320C28x 优化 C/C++ 编译器用户指南中的第 3.16 节“正在执行什么样的优化?”
4.2.1.示例¶
4.2.1.1.表达式简化¶
int32_ttest(int32_ta,int32_tb,int32_tc,int32_td){int32_ttmp;if(d>0)tmp=(a*b)+(a*c);elsetmp=(a*b);returntmp;}
列表 4.4 中的源代码中有 3 个 32 位乘法,需要 IMPYL
指令。在 -O2
处,编译器能够简化表达式以生成 1 条 IMPYL
指令,而不进行优化则为 3 条。
优化级别 | 所生成汇编代码中的 IMPYL 数 |
---|---|
-Ooff | 3 |
-O0、-O1 | 2 |
-O2 | 1 |
4.2.1.2.常量传播和折叠¶
1 2 3 4 5 6 7 8 9 10 11 12 13 | int32_tconstant(int32_tc,int32_td){int32_ta=42;int32_tb=10;int32_ttmp;if(d>0)tmp=(a*b)+(a*c);elsetmp=(a*b);returntmp;} |
这种优化将常量的值传播到表达式中并预先计算常量表达式的结果。
在 -O2
及更高级别,编译器将表达式替换为:
(d>0L)? (tmp=(c+10L)*42L): (tmp=420L);
即,它将 a
和 b
的值传播到第 8、10 行的表达式中,并在第 10 行计算 a*b
,将表达式替换为常数 420
。
4.2.1.3.删除未使用的赋值¶
1 2 3 4 5 6 7 8 9 10 11 | int32_tunused_asg(int32_ta,int32_tb,int32_tc,int32_td){int32_ttmp=42;if(d>0)tmp=(a*b)+(a*c);elsetmp=(a*b);returntmp;} |
在列表 4.6 中,不需要在第 3 行对 tmp
赋值,因为随后分别在第 6 行和第 8 行的 if 和 else 路径上对 tmp
赋值。在 -O0
及更高级别,编译器会删除赋值。
这提高了性能,因为删除了不需要保证正确性的表达式,从而减少了循环数。
4.2.1.4.自动增量寻址¶
int32_taddressing(int32_t*array,int16_tN){int32_tsum=0;int32_ti=0;_nassert(N>0);for(i=0;i<N;i++)sum+=array[i];returnsum;}
在 -O2
及更高级别,编译器会为列表 4.7 中的循环生成高效的自动递增寻址模式,从而减少执行循环的指令:12 条指令(在 -O1
)与 8 条(在 -O2
)。
-O1 |
-O2 生成高效的 *XARn++ 寻址 |
---|---|
||$C$L7||: ;*** g2: ;*** sum += array[i]; ;*** if ( (++i) < (long)N ) goto g2; MOVL ACC,XAR5 LSL ACC,1 ADDL ACC,XAR4 MOVL XAR6,ACC ADDB XAR5,#1 MOVL ACC,P ADDL ACC,*+XAR6[0] MOVL P,ACC MOV AL,AR7 MOV ACC,AL CMPL ACC,XAR5 B ||$C$L7||,GT |
||$C$L7||: ;*** g2: ;*** sum += *U$7++; ;*** if ( (--L$1) != (-1L) ) goto g2; MOVL ACC,XAR6 SUBB XAR5,#1 ADDL ACC,*XAR4++ MOVL XAR6,ACC MOVB ACC,#0 SUBB ACC,#1 CMPL ACC,XAR5 B ||$C$L7||,NEQ |
4.2.1.5.消除无效代码¶
int32_tdce(int32_ta,int32_tb,int32_tc,int32_td){int32_ttmp1=a*b*c*d;int32_ttmp;if(d>0)tmp=(a*b)+(a*c);elsetmp=(a*b);returntmp;}
在列表 4.8 中,计算出并分配给 tmp1
的表达式是无效的,因为 tmp1
未用在函数中的任何位置。消除无效代码是一种用于删除未使用表达式的编译器技术。在 -Ooff
时,生成的汇编代码包含 6 条 IMPYL
指令,对应于源代码中的每个乘数。在 -O0
时,编译器能够优化代码,并使用无效代码消除和表达式简化的组合将生成的 IMPYL
数量减少到 2 个。
(d>0L)? (tmp=(b+c)*a): (tmp=a*b);
4.2.2.代码大小与速度权衡¶
有关代码大小与速度权衡的详细信息,请参阅 TMS320C28x 优化 C/C++ 编译器用户指南中的第 3.2 节“控制代码大小与速度”。
4.2.3.优化级别和调试¶
在更高级别的优化中,调试(例如单步)应用程序变得越来越困难。这是因为在更高的优化级别,编译器会对应用程序进行转换以减少其执行时间、存储器容量占用、功耗或这些的组合。这些转换显著改变了代码的布局,使调试器难以或无法识别与一组汇编指令相对应的源代码。
理想方法是在禁用优化的情况下执行初始开发和调试,然后启用优化。有关详细信息,请参阅启用调试。
4.2.4.优化器 interlist¶
优化会使正常的源代码 interlist 处理变得不现实,因为编译器会大幅度重新排列程序。
--src_interlist
选项会将编译器注释与汇编源语句交叉列出。在启用优化的情况下使用此选项时,interlist 功能不会作为单独的通道运行。相反,编译器会在代码中插入注释,指示编译器如何重新排列并优化了代码。这些注释在汇编语言文件中显示为以 ;**
开头的注释。
C 源代码 | 汇编文件中的 Interlist 输出 |
---|---|
floatfmac(float*farray,intN){inti;floatsum=0.0f;#pragma MUST_ITERATE(4, , 4)#pragma UNROLL(2)for(i=1;i<N;i++)sum+=farray[i]*farray[i-1];returnsum;} |
||fmac||: ;*** ----------------------- U$13 = farray; ;*** ----------------------- L$1 = (N>>1)-1; ;*** 31 ----------------------- sum = 0.0F; ;*** ----------------------- #pragma MUST_ITERATE(2, 16382, 2) ;*** ----------------------- #pragma UNROLL(1L) ;*** ----------------------- // LOOP BELOW UNROLLED BY FACTOR(2) ;*** ----------------------- #pragma LOOP_FLAGS(4103u) ;*** -----------------------g2: ;*** 36 ----------------------- C$1 = U$13[1]; ;*** 36 ----------------------- sum += *U$13++*C$1; ;*** 36 ----------------------- sum += U$13[1]*C$1; ;*** 35 ----------------------- ++U$13; ;*** 35 ----------------------- if ( (--L$1) != (-1) ) goto g2; ;*** 38 ----------------------- return sum; |
从表 4.4 中的列表可以清楚地看出,优化器已将循环展开 2 倍。来自源代码的原始 pragma 也已更新以考虑展开。有关循环展开的详细信息,请参阅循环展开。
警告
--c_src_interlist
选项可能会对性能和代码大小产生负面影响,因为它可以防止某些优化跨越 C/C++ 语句边界。因此,启用优化时建议使用 --src_interlist
。在 CCS 中,--src_interlist
选项位于“Build”->“C2000 Compiler”->“Advanced Options”->“Assember Options”下的“Source interlist”下拉列表中。
有关 interlist 选项的详细信息,请参阅 TMS320C28x 优化 C/C++ 编译器用户指南中的第 3.10 节“将 Interlist 功能与优化一同使用”。