《ARM编程技巧PPT》由会员分享,可在线阅读,更多相关《ARM编程技巧PPT(42页珍藏版)》请在金锄头文库上搜索。
1、1TMT H E A R C H I T E C T U R E F O R T H E D I G I T A L W O R L DARM编程技巧编程技巧2TM2103v04 C/C+ Compiler Hints & TipsAgendanARM 编译器优化编译器优化C/C+和汇编混合模式编程使用ARM编译器编码局部和全局数据讨论3TM3103v04 C/C+ Compiler Hints & Tips优化级别优化级别n使用的编译器优化级别是可选择的使用的编译器优化级别是可选择的-O0-DEBUGn关闭大多数优化.n最好的调试信息,最少的优化-O1-DEBUGRELn多数优化选项许可n给
2、一个满意的调试,好的代码密度-O2-RELEASE (default)n完全的优化n有限的调试信息,最好的代码密度n为代码大小或运行速度的优化,可选择为代码大小或运行速度的优化,可选择: -Ospace (默认的默认的)或或 -Otime.n使用使用-g 选像可包含源码级调试信息选像可包含源码级调试信息4TM4103v04 C/C+ Compiler Hints & TipsnADS 编译器在所有级别中执行一些简单的优化编译器在所有级别中执行一些简单的优化ni.e. -O0, -O1, -O2n下面是一个例子:即使用下面是一个例子:即使用-O0,多余的表达式也被清除了多余的表达式也被清除了:n
3、ATPCS标准中子程序结果返回规则n结果为32位整数,R0返回n结果为64位整数,R0,R1返回n位数更多时,用内存来传递n自动优化自动优化int f(int *p) return (*p = = *p);armcc -c -O0f MOV r1, r0 MOV r0, #1 MOV pc, lr注意:在这种情况下,可使用C的关键字volatile 强制使用这些变量5TM5103v04 C/C+ Compiler Hints & Tips使用使用 “volatile”int f(volatile int *p) return (*p = = *p);armcc -cf LDR r1,r0 LD
4、R r0,r0 CMP r1,r0 MOVNE r0,#0 MOVEQ r0,#1 MOV pc,lrint f(int *p) return (*p = = *p);f MOV r0,#1 MOV pc,lrarmcc -cn这个代码用的编译级别是:-o26TM6103v04 C/C+ Compiler Hints & Tipsn下面是一个冗余代码清除的例子,他只用了下面是一个冗余代码清除的例子,他只用了-o1的优化选项的优化选项:冗余代码的清除冗余代码的清除int dummy() int a=10, b=20; int c; c=a+b; return 0;armcc -c -O1dumm
5、y MOV r0, #0 MOV pc, lr7TM7103v04 C/C+ Compiler Hints & Tips指令编排指令编排n指令编排在高级优化选项中是有效的指令编排在高级优化选项中是有效的(-O1, -O2).n指令的重新编排是为了使要运行的代码更适合对应的核n为arm9和以后的处理器提高吞吐量(一般可达到4%),并防止互锁(interlock)n选择处理器可决定使用的运算法则,在默认情况下,使用针对ARM9的优化方案 (对ARM7的运行没有影响)n例如例如:int f(int *p, int x) return *p + x * 3; 没用指令编排没用指令编排 (-O0)使用指
6、令编排使用指令编排 (-O1,-O2)ADD r1,r1,r1,LSL #1LDR r0,r0,#0LDR r0,r0,#0ADD r1,r1,r1,LSL #1ADD r0,r0,r1 ; interlock on ARM9ADD r0,r0,r1MOV pc,lrMOV pc,lrarmcc cpu arm7tdmiarmcc cpu arm9tdmi 8TM8103v04 C/C+ Compiler Hints & TipsTail-call Optimization嵌套优化可避免在函数级里的不必要的返回在可能的情况下BL 译码成B在高级优化里有效(-O1, -O2).int main(
7、)int x = f();:int f()int y = g();return y;int g()return 10;B gBL f:MOV r0, #10MOV pc, lrBL f:STR lr,sp,#-4!BL gMOV r1,r0MOV r0,r1LDR pc,sp,#4MOV r0, #10 MOV pc, lr嵌套优化嵌套优化9TM9103v04 C/C+ Compiler Hints & Tips内嵌函数(内嵌函数(inline)n内嵌可通过删除子函数调用的开销来提高性能内嵌可通过删除子函数调用的开销来提高性能n这个这个 inline 关键字显示哪个函数将被内嵌关键字显示哪个函
8、数将被内嵌n在高级优化选项中,在高级优化选项中,ADS 1.2 编译器默认自动内嵌编译器默认自动内嵌n-Oautoinline (default -O2) n-Ono_autoline (default for -O0,-O1)n哪个函数是否被内嵌取决于:哪个函数是否被内嵌取决于:n他们是否被 _inline标示n优化的级别n-Otime / -Ospacen函数被调用的次数n如果函数在别的模块中不被调用,一个好的建议是用如果函数在别的模块中不被调用,一个好的建议是用static标识函数,否则,标识函数,否则,编译器将在内嵌译码里把该函数编译乘非内嵌的编译器将在内嵌译码里把该函数编译乘非内嵌的
9、n加代码的长度n使调试信息更复杂Example.10TM10103v04 C/C+ Compiler Hints & TipsInline exampleint 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,lrfoo 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;i
10、nt 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内嵌例子内嵌例子11TM11103v04 C/C+ Compiler Hints & TipsAgendaARM编译器的优化nC/C+和汇编混合模式编程和汇编混合模式编程使用ARM编译器编码局部和全局数据讨论12TM12103v04 C/C+ Compiler Hints & TipsC和汇编的混合编程和汇编的混合编程nC/C+ 和汇编能很容易的混合和汇编能很
11、容易的混合:n可实现在c中无法实现的处理器功能n使用新的或不支持的指令n产生更高效的代码n直接链接变量和程序直接链接变量和程序n确定符合程序调用规范n输入/输出相关的符号n编译器也可包含内嵌汇编编译器也可包含内嵌汇编n大多数arm指令集都可实现n寄存器操作数可支持任意的c/c+的表达式n内嵌汇编代码可由编译器的优化器来传递13TM13103v04 C/C+ Compiler Hints & TipsATPCS(arm/thumb程序调用规范)程序调用规范)r8r9/sbr10/slr11r12r13/spr14/lrr15/pcr0r1r2r3r4r5r6r7寄存器变量寄存器变量必须保护必须保
12、护作为函数传递的参数值作为函数传递的参数值Scratch register(corruptible)Stack PointerLink RegisterProgram Counter编译器使用一套规则的来设置寄存器的用法ARM-Thumb Procedure Call Standard or ATPCS (or APCS)CPSR 标志位可被函数调用所破坏任何和编译过的代码交互工作的汇编码在接口层必 须满足ATPCS的规范Register- 如果如果 RWPI选项有效,作为栈的基地址选项有效,作为栈的基地址- 如果软件堆栈检查有效,作为栈的限制值如果软件堆栈检查有效,作为栈的限制值- 可作为临
13、时的一个值栈一样来使用可作为临时的一个值栈一样来使用- 子程序内部调用的可改写的寄存器子程序内部调用的可改写的寄存器- 程序计数器程序计数器14TM14103v04 C/C+ Compiler Hints & Tips在在C程序中调用汇编程序中调用汇编n在汇编程序中用在汇编程序中用export name来定义来定义n在在C程序中直接调用程序中直接调用,用用EXTERN声明声明n正常链接正常链接extern void mystrcopy(char *d, const char *s);int main(void) const char *src = “Source”; char dest10;
14、. mystrcopy(dest, src); . AREA StringCopy, CODE, READONLY EXPORT mystrcopymystrcopy LDRB r2, r1, #1 STRB r2, r0, #1 CMP r2, #0 BNE mystrcopy MOV pc, lr END这里所有的参数都是可以用寄存器来传递的,所以不需要在汇编程序中使用PUSH/POP来保护CALL15TM15103v04 C/C+ Compiler Hints & Tips内嵌汇编内嵌汇编n允许使用一些不能由编译器自动生允许使用一些不能由编译器自动生成的指令成的指令:nMSR / MRS
15、n新的指令n协处理器指令n通常在关联的内嵌函数中使用通常在关联的内嵌函数中使用n使用使用C变量代替寄存器变量代替寄存器n不是一个真正的汇编文件n通过优化器实现nADS FAQ 入口入口 “Using the Inline Assembler”#define Q_Flag 0x08000000 / Bit 27_inline void Clear_Q_flag (void) int temp;_asm MRS temp, CPSR BIC temp, temp, #Q_Flag MSR CPSR_f, temp_inline int mult16(short a, short b, int c)
16、int temp;_asm SMLABB temp,a,b,c return temp;16TM16103v04 C/C+ Compiler Hints & TipsAgenda ARM编译器的优化C/C+和汇编混合模式编程n使用使用ARM编译器编码编译器编码局部和全局数据讨论17TM17103v04 C/C+ Compiler Hints & Tips参数传递参数传递n开始四个字大小的参数直接使用寄存器的开始四个字大小的参数直接使用寄存器的R0-R3来传递来传递(快速且高效的快速且高效的)n更多的信息可参看ATPCSn如果需要更多的参数,将使用堆栈。如果需要更多的参数,将使用堆栈。(需要额外
17、的指令和慢速的存储器操需要额外的指令和慢速的存储器操作作)n所以通常限制参数的个数,使它为所以通常限制参数的个数,使它为4或更少。或更少。n如果不可避免,把常用的参数前4个放在R0-R3中Example.18TM18103v04 C/C+ Compiler Hints & TipsnParameter Passing (4 parameters)int func1(int a, int b, int c, int d) return a+b+c+d;int caller1(void) return func1(1,2,3,4); func1 0x000000 : ADD r0,r0,r1 0x
18、000004 : ADD r0,r0,r2 0x000008 : ADD r0,r0,r3 0x00000c : MOV pc,lr caller1 0x000014 : MOV r3,#4 0x000018 : MOV r2,#3 0x00001c : MOV r1,#2 0x000020 : MOV r0,#1 0x000024 : B func1Parameter Passing (4 parameters)19TM19103v04 C/C+ Compiler Hints & TipsParameter Passing (6 parameters)nParameter Passing (
19、6 parameters)func2 0x000000 : STR lr, sp,#-4! 0x000004 : ADD r0,r0,r1 0x000008 : ADD r0,r0,r2 0x00000C : ADD r0,r0,r3 0x000010 : LDMIB sp,r12,r14 0x000014 : ADD r0,r0,r12 0x000018 : ADD r0,r0,r14 0x00001C : LDR pc,sp,#4 caller2 0x000020 : STMFD sp!,r2,r3,lr 0x000024 : MOV r3,#6 0x000028 : MOV r2,#5
20、0x00002C : STMIA sp,r2,r3 0x000030 : MOV r3,#4 0x000034 : MOV r2,#3 0x000038 : MOV r1,#2 0x00003C : MOV r0,#1 0x000040 : BL func2 0x000044 : LDMFD sp!,r2,r3,pcint func2(int a,int b,intc, int,d,int e,int f) return a+b+c+d+e+f;int caller2(void) return func1(1,2,3,4,5,6);This code is compiled with “-O2
21、 -Ono_autoinline”20TM20103v04 C/C+ Compiler Hints & Tips循环终止循环终止n在在for(), while() dowhile()的循环中,用减到的循环中,用减到0代替加到某个值。代替加到某个值。n比如,用下面的代替比如,用下面的代替 :for (loop = 1; loop = total; loop+) /(ADD,CMP)代替为:代替为: for (loop = total; loop != 0; loop-) /(SUBS)n尽量减少循环的次数尽量减少循环的次数n代码小,且使用更少的寄存器Example.21TM21103v04 C/
22、C+ Compiler Hints & TipsLoop TerminationCount upint fact1(int limit) int i; int fact = 1; for (i = 1; i = 60) count = 0;modulo ADD r1,r0,#1 MOV r0,#0x3c BL _rt_udiv MOV r0,r1test_and_reset ADD r0,r0,#1 CMP r0,#0x3c MOVCS r0,#0 这个代码用“-O1 -Ospace”编译25TM25103v04 C/C+ Compiler Hints & Tips浮点浮点n软件浮点库软件浮点
23、库 (fplib)n默认:-fpu softvfp (or softfpa)n浮点协处理器浮点协处理器nVFP (ARM10 and ARM9)n-fpu vfp (or vfpv1 or vfpv2)nFPA (eg ARM7 500fe) - now obsoleten-fpu fpan软件浮点仿真软件浮点仿真 (FPE)n通过未定义的异常来捕获协处理器指令nVFP (and FPA) 实际上是硬件协处理器和仿真的混合实际上是硬件协处理器和仿真的混合n要求支持代码去实现混合运算n在AFS 1.3 和以后的版本里有VFP的 支持代码, 在ADS的FPA里.n在在thumb代码使用代码使用fp
24、处,处, vfp系统用系统用-fpu softvfp+vfp编译编译n使用使用 -auto_float_constants 预防常量被处理为双精度类型,关闭警告用预防常量被处理为双精度类型,关闭警告用 -Wk.Example.26TM26103v04 C/C+ Compiler Hints & Tipsfloat foo(float num1, float num2) float temp, temp2; temp = num1 + num2; temp2 = num2 * num2; return temp2-temp;armcc float.cfoo FADDS s0,s0,s1 FMUL
25、S s1,s1,s1 FSUBS s0,s1,s0 MOV pc,lr使用协处理器指令使用协处理器指令foo STMFD sp!,r3-r5,lr MOV r4,r1 BL _fadd MOV r5,r0 MOV r0,r4 MOV r1,r4 BL _fmul MOV r1,r5 LDMFD sp!,r3-r5,lr B _fsub使用浮点库使用浮点库armcc -fpu vfpv2 float.cFloating point examples27TM27103v04 C/C+ Compiler Hints & TipsAgenda ARM 编译器优化C/C+和汇编混合模式编程使用ARM编译
26、器编码局部和全局数据局部和全局数据28TM28103v04 C/C+ Compiler Hints & Tips变量类型变量类型n全局和静态变量保留在全局和静态变量保留在RAM里里n需使用loads/stores访问外部存储器n局部变量通常放在寄存器中,用来快速且高效的处理局部变量通常放在寄存器中,用来快速且高效的处理n如果编译器的寄存器分配算法认为超过现有的寄存器数量,将把变量压入栈中n对局部变量,用对局部变量,用 word-sized (int) 代替代替 halfword 和和 byte:n为了确保不受其他条件的影响,可特别指定使用32-bit寄存器变量.29TM29103v04 C/C
27、+ Compiler Hints & Tipsint wordsize(int a) wordsize 0x000000 : MOV r0,r0,LSL #1 return (a*2); 0x000004 : MOV pc,lrshort halfsize(short b) halfsize 0x000008 : MOV r0,r0,LSL #17 return (b*2); 0x00000c : MOV r0,r0,ASR #16 0x000010 : MOV pc,lrchar bytesize(char c) bytesize 0x000014 : MOV r0,r0,LSL #25 r
28、eturn (c*2); 0x000018 : MOV r0,r0,LSR #24 0x00001c : MOV pc,lr变量大小变量大小30TM30103v04 C/C+ Compiler Hints & Tips堆栈的用法堆栈的用法nC/C+代码的堆栈使用代码的堆栈使用,堆栈用来保留堆栈用来保留:n子程序的返回地址n溢出的局部变量n局部数组和结构体n注意注意:n函数越小越好: (更少的变量,更少的溢出);n更少数量的live变量 (比如:函数里每个点保存的有用的数据)n避免使用大的局部结构体或数组 (使用malloc/free代替)n避免递归31TM31103v04 C/C+ Compi
29、ler Hints & Tips堆栈使用估计堆栈使用估计n链接使用链接使用 -callgraphn显示静态堆栈的开销(html文件). n编译时使用软件堆栈检查编译时使用软件堆栈检查n-apcs /swstn在栈结束点设置在栈结束点设置 watchpointn测试堆栈n定义大的栈定义大的栈n填充某个值,看覆盖了多少,从而判定栈的使用情况nARMulator映射文件映射文件n拒绝访问栈下面的区域,栈溢出将导致一个data abort异常ARMulator模式, 跟踪堆栈的大小,用ARMulator的统计来输出报告当要对堆栈使用情况进行估计时,使用worst case32TM32103v04 C/
30、C+ Compiler Hints & Tips全局数据布局全局数据布局char one;short two;char three;int four;charshortintchare.g. 声明的数据Declared alignment12 bytes(4 bytes of padding)Optimal alignment8 bytes(Zero bytes of padding)ADS 1.1+ 将自动用此风格排序shortcharcharintn全局数据保存在存储器里,不是寄存器全局数据保存在存储器里,不是寄存器n需要load / store指令来访问n用物理尺寸的边界对齐nADS 1
31、.2 会优化在一个模块里的全局数据的布局会优化在一个模块里的全局数据的布局n用-Ono_data_reorder 将关闭排序33TM33103v04 C/C+ Compiler Hints & Tips不对齐访问不对齐访问nARM硬件需要在自然尺寸的边界访问内存硬件需要在自然尺寸的边界访问内存nWord访问在word尺寸nHalfword访问在halfword尺寸nByte访问在byte尺寸n不对齐访问不对齐访问n遗留代码n特定协议需要必须告诉编译器,让它产生适当的指令序列需要必须告诉编译器,让它产生适当的指令序列n使用使用 _packed 属性属性n可能导致多字节访问代替单字节访问n用LDM
32、指令的结果有2 字,转变为生成单字n不对齐数据的访问所产生的意外的结果取决于指令的使用不对齐数据的访问所产生的意外的结果取决于指令的使用n将是不可预知的34TM34103v04 C/C+ Compiler Hints & Tips指针的对齐指针的对齐n必须非常小心指针的对齐必须非常小心指针的对齐n可能导致程序的失败memcpy inlinedmemcpy calledmemcpy inlinedunsafelymemcpy called safely#include int *a = (int *)0x1000;int *b = (int *)0x2000;char *c = (char *)
33、0x3001;_packed int *d;void foo (void) memcpy (b,a,12); memcpy (c,a,12); b = (int *)c; memcpy (b,a,12); d = (_packed int *)c; memcpy (void *)d,a,12);STMFD r13!,r4,r14LDR r4,0x58LDR r1,r4,#0LDR r0,r4,#4LDMIA r1,r2,r3,r12STMIA r0,r2,r3,r12LDR r0,r4,#8LDR r1,r4,#0MOV r2,#0xcBL _rt_memcpyLDR r0,r4,#8STR
34、r0,r4,#4LDR r1,r4,#0LDMIA r1,r2,r3,r12STMIA r0,r2,r3,r12LDR r0,r4,#8LDR r1,0x5cMOV r2,#0xcSTR r0,r1,#0LDR r1,r4,#0BL _rt_memcpyLDMFD r13!,r4,pc35TM35103v04 C/C+ Compiler Hints & Tips结构的打包结构的打包n在结构里定义打包的元素代替结构的打包在结构里定义打包的元素代替结构的打包n他将帮助减小访问输出的结构的开销nADS FAQ 入口: Aligned v. unaligned accesses and use of
35、_packed_packed struct mystruct int aligned_i; short aligned_s; int unaligned_i;extern struct mystruct S;shortintU_intU_intstruct mystruct int aligned_i; short aligned_s; _packed int unaligned_i;extern struct mystruct S;PREFER._packed限定的数据为限定的数据为1字节对齐字节对齐不实现字节对齐调整不实现字节对齐调整很高的访问代价,不会节省存储空间很高的访问代价,不会节省
36、存储空间36TM36103v04 C/C+ Compiler Hints & Tips优化的指针基地址优化的指针基地址extern int a;extern int b;void foo (int x, int y) a = x; b = y; baLDR r2, pc,#12STR r0, r2,#0LDR r3, pc,#8STR r1, r3,#0MOV pc, lrDCD “address of a”DCD “address of b”a 和 b 被定义为外部的注意:在用-o0时无效LDR r2, pc,#8STR r0, r2,#0STR r1, r2,#4MOV pc, lrDCD
37、 “base address of a and b”a 和 b 被定义为模块内用的数据int a;int b; void foo (int x, int y) a = x; b = y; 37TM37103v04 C/C+ Compiler Hints & Tips优化外部全局指针优化外部全局指针n如果全局数据放在结构体里,每个元素的访问将自动的在基指针上偏移如果全局数据放在结构体里,每个元素的访问将自动的在基指针上偏移n在结构体里的元素将按大小的边界对齐n编译器不对结构体重新排列n把数据放在多个逻辑结构体内,代替一个大的结构把数据放在多个逻辑结构体内,代替一个大的结构n#define 将对主
38、应用代码的改变隐藏起来将对主应用代码的改变隐藏起来n#define value mystruct.valueExample.38TM38103v04 C/C+ Compiler Hints & Tips外部全局变量外部全局变量extern int a;extern int b;int main(void) return a+b;int a;int b;mainLDR r0,0x000080c0000080acLDR r1,0x000080c4000080b0LDR r0,r0,#0000080b4LDR r1,r1,#0000080b8ADD r0,r0,r1000080bcMOV pc,lr
39、000080c0DCD 0x000083d4000080c4DCD 0x000083d8extern struct data mystruct;int main(void) return mystruct.a+mystruct.b;struct data int a; int b;mystruct;mainLDR r0,0x000080bc000080acLDR r1,r0,#0000080b0LDR r0,r0,#4000080b4ADD r0,r1,r0000080b8MOV pc,lr000080bcDCD 0x000083ccdata.ccode.cAssembler output39
40、TM39103v04 C/C+ Compiler Hints & Tips测验测验1) 默认的优化级别是什么?默认的优化级别是什么?2)给)给tail-call优化有什么好处优化有什么好处3) 在函数调用时,管理寄存器用法的标准的名字是什么?在函数调用时,管理寄存器用法的标准的名字是什么?4) 在参数传递时,被推荐的最大的量是多少?在参数传递时,被推荐的最大的量是多少?5) 为什么在为什么在arm里要尽可能避免使用除法?里要尽可能避免使用除法?6) _packed的效果是什么?的效果是什么?40TM40103v04 C/C+ Compiler Hints & Tips参考参考n需要更多的信息,
41、请看需要更多的信息,请看:nADS 1.2 Compilers and Libraries GuidenSection 2 : C and C+ CompilersnSection 3 : ARM Compiler ReferencenADS 1.2 Developer GuidenChapter 4: Mixing C, C+ and Assembly LanguagenApplication Note 34, Writing Efficient CnApplication Note 36, Declaring Global Data in C 刚才的发言,如刚才的发言,如有不当之处请多指有不当之处请多指正。谢谢大家!正。谢谢大家!42