ARM ARM 编程技巧 TH E AR C H T E C UR E F O R THE D G IT A L W。RLD
1 T H E A R C H I T E C T U R E F O R TTM H E D I G I T A L W O R L D ARM 编程技巧
ARM Agenda ■ARM编译器优化 CC++和汇编混合模式编程 使用ARM编译器编码 局部和全局数据讨论 103v04 C/C++ Compiler Hints & Tips
2 103v04 C/C++ Compiler Hints & Tips TM 2 Agenda ◼ ARM 编译器优化 C/C++和汇编混合模式编程 使用ARM编译器编码 局部和全局数据讨论
ARM 优化级别 使用的编译器优化级别是可选择的 O0---DEBUG 关闭大多数优化 最好的调试信息,最少的优化 O1--DEBUGREL 多数优化选项许可 给一个满意的调试,好的代码密度 -O2---RELEASE(default) 完全的优化 ■有限的调试信息,最好的代码密度 ■为代码大小或运行速度的优化,可选择: Ospace(默认的)或- Time 使用-g选像可包含源码级调试信息 103v04 C/C++ Compiler Hints & Tips
3 103v04 C/C++ Compiler Hints & Tips TM 3 优化级别 ◼ 使用的编译器优化级别是可选择的 -O0---DEBUG ◼ 关闭大多数优化. ◼ 最好的调试信息,最少的优化 -O1---DEBUGREL ◼ 多数优化选项许可 ◼ 给一个满意的调试,好的代码密度 -O2---RELEASE (default) ◼ 完全的优化 ◼ 有限的调试信息,最好的代码密度 ◼ 为代码大小或运行速度的优化,可选择:-Ospace (默认的)或-Otime. ◼ 使用-g 选像可包含源码级调试信息
ARM 自动优化 ■ADs编译器在所有级别中执行一些简单的优化 ■e.-o0,-1,-02 下面是一个例子:即使用-O0,多余的表达式也被清除了 ■ ATPCS标准中子程序结果返回规则 结果为32位整数,RO返回 结果为64位整数,RO,RI返回 ■位数更多时,用内存来传递 int f(int *p) armcc -C -O0 Mov rl, ro return (*p==*p) MoV ro,#1 1 注意:在这种情况下,可使用C的关键字 volatile强制使用这些变量 103v04 C/C++ Compiler Hints & Tips
4 103v04 C/C++ Compiler Hints & Tips TM 4 ◼ ADS 编译器在所有级别中执行一些简单的优化 ◼ i.e. -O0, -O1, -O2 ◼ 下面是一个例子:即使用-O0,多余的表达式也被清除了: ◼ ATPCS标准中子程序结果返回规则 ◼ 结果为32位整数,R0返回 ◼ 结果为64位整数,R0,R1返回 ◼ 位数更多时,用内存来传递 ◼ …… 自动优化 int f(int *p) { return (*p = = *p); } armcc -c -O0 f MOV r1, r0 MOV r0, #1 MOV pc, lr 注意:在这种情况下,可使用C的关键字volatile 强制使用这些变量
ARM 使用“ volatile” int f(int *p) return (*p ★ ancc·c MOV r0,#1 Mov pc,lr LDR rl [ro]] int f(volatile int *p) LDR ro,[ro ancc·c CMP x1,x0 return (*p==*p) MOVNE ro, #O MOVEQ r0,#1 pc,I 这个代码用的编译级别是:-02 103v04 C/C++ Compiler Hints & Tips
5 103v04 C/C++ Compiler Hints & Tips TM 5 使用 “volatile” int f(volatile int *p) { return (*p = = *p); } armcc -c f LDR r1,[r0] LDR r0,[r0] CMP r1,r0 MOVNE r0,#0 MOVEQ r0,#1 MOV pc,lr int f(int *p) { return (*p = = *p); } f MOV r0,#1 MOV pc,lr armcc -c ◼ 这个代码用的编译级别是:-o2
ARM 冗余代码的清除 ■下面是一个冗余代码清除的例子,他只用了-01的优化选项 int dummy () inta=10,b=20; dummy n七 armcc -C -O1 Moⅴr0,#0 Mov pc, lr 103v04 C/C++ Compiler Hints & Tips
6 103v04 C/C++ Compiler Hints & Tips TM 6 ◼ 下面是一个冗余代码清除的例子,他只用了-o1的优化选项: 冗余代码的清除 int dummy() { int a=10, b=20; int c; c=a+b; return 0; } armcc -c -O1 dummy MOV r0, #0 MOV pc, lr
ARM 指令编排 指令编排在高级优化选项中是有效的(-01,O2) ■指令的重新编排是为了使要运行的代码更适合对应的核 为arm9和以后的处理器提高吞吐量(一般可达到4%),并防止互锁( interlock) 选择处理器可决定使用的运算法则,在默认情况下,使用针对ARM9的优化方案 (对ARM7的运行没有影响) 例如: int f(int *p, int x) t return *p +x *3; 1 没用指令编排(-O0) 使用指令编排(O1,O2) ADD r1, r1, r1, LSL #1 LDRr0,[r0,#0] LDRx0,[r0,#0] ADD r1,r1, r1, LSL #1 ADD ro,ro, rl interlock on ARM9 ADDx0,x0,x¥1 Mov pc,lr Mov pc,lr armcc-cpu arm7tdmi armcc -cpu arm9tdmi 103v04 C/C++ Compiler Hints & Tips
7 103v04 C/C++ Compiler Hints & Tips TM 7 指令编排 ◼ 指令编排在高级优化选项中是有效的(-O1, -O2). ◼ 指令的重新编排是为了使要运行的代码更适合对应的核 ◼ 为arm9和以后的处理器提高吞吐量(一般可达到4%),并防止互锁(interlock) ◼ 选择处理器可决定使用的运算法则,在默认情况下,使用针对ARM9的优化方案 (对ARM7的运行没有影响) ◼ 例如: int f(int *p, int x) { return *p + x * 3; } 没用指令编排 (-O0) 使用指令编排 (-O1,-O2) ADD r1,r1,r1,LSL #1 LDR r0,[r0,#0] LDR r0,[r0,#0] ADD r1,r1,r1,LSL #1 ADD r0,r0,r1 ; interlock on ARM9 ADD r0,r0,r1 MOV pc,lr MOV pc,lr armcc –cpu arm7tdmi armcc –cpu arm9tdmi
ARM 嵌套优化 嵌套优化可避免在函数级里的不必要的返回 在可能的情况下BL译码成B 在高级优化里有效(O1,-O2) int main o int fo int go ntx =fo int y =goi return 10 return y Bl f sTR1x,[sp,#-4]! MOv r0, #10 g Mov pc,lr Mor1,x0、 Mov ro rl LDR pc, [sp], #4 L E MOv r0, #10 103v04 C/C++ Compiler Hints & Tips
8 103v04 C/C++ Compiler Hints & Tips TM 8 Tail-call Optimization 嵌套优化可避免在函数级里的不必要的返回 在可能的情况下BL 译码成B 在高级优化里有效(-O1, -O2). int main() { int x = f(); : } int f() { int y = g(); return y; } int g() { return 10; } BL f B g : MOV r0, #10 MOV pc, lr BL f : STR lr,[sp,#-4]! BL g MOV r1,r0 MOV r0,r1 LDR pc,[sp],#4 MOV r0, #10 MOV pc, lr 嵌套优化
ARM 内嵌函数( inline) ■内嵌可通过删除子函数调用的开销来提高性能 这个in1ine关键字显示哪个函数将被内嵌 在高级优化选项中,ADS12编译器默认自动内嵌 Oautoinline(default -02) Ono autoline(default for-00, -o1) ■哪个函数是否被内嵌取决于: ■他们是否被 inline标示 优化的级别 time/-Ospace 函数被调用的次数 ■如果函数在别的模块中不被调用,一个好的建议是用 static标识函数,否则, 编译器将在内嵌译码里把该函数编译乘非内嵌的 加代码的长度 使调试信息更复杂 Example 103v04 C/C++ Compiler Hints & Tips
9 103v04 C/C++ Compiler Hints & Tips TM 9 内嵌函数(inline) ◼ 内嵌可通过删除子函数调用的开销来提高性能 ◼ 这个 inline 关键字显示哪个函数将被内嵌 ◼ 在高级优化选项中,ADS 1.2 编译器默认自动内嵌 ◼ -Oautoinline (default -O2) ◼ -Ono_autoline (default for -O0,-O1) ◼ 哪个函数是否被内嵌取决于: ◼ 他们是否被 __inline标示 ◼ 优化的级别 ◼ -Otime / -Ospace ◼ 函数被调用的次数 ◼ 如果函数在别的模块中不被调用,一个好的建议是用static标识函数,否则, 编译器将在内嵌译码里把该函数编译乘非内嵌的 ◼ 加代码的长度 ◼ 使调试信息更复杂 Example
ARM 内嵌例子 nt bar(int a) bar ADD r0,x0,#5 a=a+5; return a foo 1r,[sp,#-4]! bar intf。。(inti) r0,x0,# i=bar (i) r0,x0,#1 主=i-2; LDR pc,[sP],#4 i=bar (i) inline int bar (int a) a=a+5; SUB r0,¥0,#2 return a r0,x0,#5 MOV ,lr int foo (int i=bar (i)i i=i-2 return i 103v04 C/C++ Compiler Hints & Tips 10
10 103v04 C/C++ Compiler Hints & Tips TM 10 Inline example int bar(int a) { a=a+5; return a; } int foo(int i) { i=bar(i); i=i-2; i=bar(i); i++; return i; } bar ADD r0,r0,#5 MOV pc,lr foo STR lr,[sp,#-4]! BL bar SUB r0,r0,#2 BL bar ADD r0,r0,#1 LDR pc,[sp],#4 __inline int bar(int a) { a=a+5; return a; } int foo(int i) { i=bar(i); i=i-2; i=bar(i); i++; return i; } foo ADD r0,r0,#5 SUB r0,r0,#2 ADD r0,r0,#5 ADD r0,r0,#1 MOV pc,lr 内嵌例子