确定符合程序调用规范.ppt

上传人:牧羊曲112 文档编号:6008863 上传时间:2023-09-14 格式:PPT 页数:41 大小:213.50KB
返回 下载 相关 举报
确定符合程序调用规范.ppt_第1页
第1页 / 共41页
确定符合程序调用规范.ppt_第2页
第2页 / 共41页
确定符合程序调用规范.ppt_第3页
第3页 / 共41页
确定符合程序调用规范.ppt_第4页
第4页 / 共41页
确定符合程序调用规范.ppt_第5页
第5页 / 共41页
点击查看更多>>
资源描述

《确定符合程序调用规范.ppt》由会员分享,可在线阅读,更多相关《确定符合程序调用规范.ppt(41页珍藏版)》请在三一办公上搜索。

1、ARM编程技巧,Agenda,ARM 编译器优化C/C+和汇编混合模式编程使用ARM编译器编码局部和全局数据讨论,优化级别,使用的编译器优化级别是可选择的-O0-DEBUG关闭大多数优化.最好的调试信息,最少的优化-O1-DEBUGREL多数优化选项许可给一个满意的调试,好的代码密度-O2-RELEASE(default)完全的优化有限的调试信息,最好的代码密度为代码大小或运行速度的优化,可选择:-Ospace(默认的)或-Otime.使用-g 选像可包含源码级调试信息,ADS 编译器在所有级别中执行一些简单的优化i.e.-O0,-O1,-O2下面是一个例子:即使用-O0,多余的表达式也被清除

2、了: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 强制使用这些变量,使用“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

3、(int*p)return(*p=*p);,f MOV r0,#1 MOV pc,lr,armcc-c,这个代码用的编译级别是:-o2,下面是一个冗余代码清除的例子,他只用了-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,指令编排,指令编排在高级优化选项中是有效的(-O1,-O2).指令的重新编排是为了使要运行的代码更适合对应的核为arm9和以后的处理器提高吞吐量(一般可达到4%),并防止互锁(interlock)选择处理器可决定使用的运算

4、法则,在默认情况下,使用针对ARM9的优化方案(对ARM7的运行没有影例如:int f(int*p,int x)return*p+x*3;没用指令编排(-O0)使用指令编排(-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,lr,armcc cpu arm7tdmi,armcc cpu arm9tdmi,Tail-call Optimization,嵌套优化可避免在函数级里的不必要的返回在可能的

5、情况下BL 译码成B在高级优化里有效(-O1,-O2).,int main()int x=f();:,int f()int y=g();return y;,int g()return 10;,嵌套优化,内嵌函数(inline),内嵌可通过删除子函数调用的开销来提高性能这个 inline 关键字显示哪个函数将被内嵌在高级优化选项中,ADS 1.2 编译器默认自动内嵌-Oautoinline(default-O2)-Ono_autoline(default for-O0,-O1)哪个函数是否被内嵌取决于:他们是否被 _inline标示优化的级别-Otime/-Ospace函数被调用的次数如果函数在

6、别的模块中不被调用,一个好的建议是用static标识函数,否则,编译器将在内嵌译码里把该函数编译乘非内嵌的加代码的长度使调试信息更复杂,Example.,Inline example,内嵌例子,Agenda,ARM编译器的优化C/C+和汇编混合模式编程使用ARM编译器编码局部和全局数据讨论,C和汇编的混合编程,C/C+和汇编能很容易的混合:可实现在c中无法实现的处理器功能使用新的或不支持的指令产生更高效的代码直接链接变量和程序确定符合程序调用规范输入/输出相关的符号编译器也可包含内嵌汇编大多数arm指令集都可实现寄存器操作数可支持任意的c/c+的表达式内嵌汇编代码可由编译器的优化器来传递,AT

7、PCS(arm/thumb程序调用规范),r8,r9/sb,r10/sl,r11,r12,r13/sp,r14/lr,r15/pc,r0,r1,r2,r3,r4,r5,r6,r7,寄存器变量必须保护,作为函数传递的参数值,Scratch register(corruptible),Stack PointerLink RegisterProgram Counter,编译器使用一套规则的来设置寄存器的用法ARM-Thumb Procedure Call Standard or ATPCS(or APCS)CPSR 标志位可被函数调用所破坏任何和编译过的代码交互工作的汇编码在接口层必 须满足ATPC

8、S的规范,Register,-如果 RWPI选项有效,作为栈的基地址,-如果软件堆栈检查有效,作为栈的限制值,-可作为临时的一个值栈一样来使用,-子程序内部调用的可改写的寄存器,-程序计数器,在C程序中调用汇编,在汇编程序中用export name来定义在C程序中直接调用,用EXTERN声明正常链接,extern void mystrcopy(char*d,const char*s);int main(void)const char*src=“Source”;char dest10;.mystrcopy(dest,src);.,AREA StringCopy,CODE,READONLY EXP

9、ORT mystrcopymystrcopy LDRB r2,r1,#1 STRB r2,r0,#1 CMP r2,#0 BNE mystrcopy MOV pc,lr END,这里所有的参数都是可以用寄存器来传递的,所以不需要在汇编程序中使用PUSH/POP来保护,CALL,内嵌汇编,允许使用一些不能由编译器自动生成的指令:MSR/MRS新的指令协处理器指令通常在关联的内嵌函数中使用使用C变量代替寄存器不是一个真正的汇编文件通过优化器实现ADS FAQ 入口“Using the Inline Assembler”,#define Q_Flag 0 x08000000/Bit 27_inlin

10、e 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)int temp;_asm SMLABB temp,a,b,c return temp;,Agenda,ARM编译器的优化C/C+和汇编混合模式编程使用ARM编译器编码局部和全局数据讨论,参数传递,开始四个字大小的参数直接使用寄存器的R0-R3来传递(快速且高效的)更多的信息可参看ATPCS如果需要更多的参数,将使用堆栈。(需要额外的指

11、令和慢速的存储器操作)所以通常限制参数的个数,使它为4或更少。如果不可避免,把常用的参数前4个放在R0-R3中,Example.,Parameter 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 0 x000000:ADD r0,r0,r1 0 x000004:ADD r0,r0,r2 0 x000008:ADD r0,r0,r3 0 x00000c:MOV pc,lr caller1 0 x000014:MO

12、V r3,#4 0 x000018:MOV r2,#3 0 x00001c:MOV r1,#2 0 x000020:MOV r0,#1 0 x000024:B func1,Parameter Passing(4 parameters),Parameter Passing(6 parameters),Parameter Passing(6 parameters),func2 0 x000000:STR lr,sp,#-4!0 x000004:ADD r0,r0,r1 0 x000008:ADD r0,r0,r2 0 x00000C:ADD r0,r0,r3 0 x000010:LDMIB sp,

13、r12,r14 0 x000014:ADD r0,r0,r12 0 x000018:ADD r0,r0,r14 0 x00001C:LDR pc,sp,#4 caller2 0 x000020:STMFD sp!,r2,r3,lr 0 x000024:MOV r3,#6 0 x000028:MOV r2,#5 0 x00002C:STMIA sp,r2,r3 0 x000030:MOV r3,#4 0 x000034:MOV r2,#3 0 x000038:MOV r1,#2 0 x00003C:MOV r0,#1 0 x000040:BL func2 0 x000044:LDMFD sp!,

14、r2,r3,pc,int 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-Ono_autoinline”,循环终止,在for(),while()dowhile()的循环中,用减到0代替加到某个值。比如,用下面的代替:for(loop=1;loop=total;loop+)/(ADD,CMP)代替为:for(loop=total;loop!=0;loop-)/(SUBS)尽量减

15、少循环的次数代码小,且使用更少的寄存器,Example.,Loop Termination,Count upint fact1(int limit)int i;int fact=1;for(i=1;i=limit;i+)fact=fact*i;return fact;,Count downint fact2(int limit)int i;int fact=1;for(i=limit;i!=0;i-)fact=fact*i;return fact;,fact2 0 x000000:MOVS r1,r0 0 x000004:MOV r0,#1 0 x000008:MOVEQ pc,lr 0 x0

16、0000c:MUL r0,r1,r0 0 x000010:SUBS r1,r1,#1 0 x000014:BNE 0 x0c 0 x000018:MOV pc,lr,fact1 0 x000000:MOV r2,#1 0 x000004:MOV r1,#1 0 x000008:CMP r0,#1 0 x00000c:BLT 0 x20 0 x000010:MUL r2,r1,r2 0 x000014:ADD r1,r1,#1 0 x000018:CMP r1,r0 0 x00001c:BLE 0 x10 0 x000020:MOV r0,r2 0 x000024:MOV pc,lr,This

17、code is compiled with“-O2-Otime”,除法操作(1),ARM核不含除法硬件除法通常用一个运行库函数来实现运行需要很多的周期,unsigned div(unsigned a,unsigned b)return(b/a);,div B _rt_udiv,unsigned div2(unsigned b)return(b/2);,div2 MOV r0,r0,LSR#1 MOV pc,lr,一些除法操作在编译时作为特例来处理除2操作,被左移代替,除法操作(2),在-O1和-O2(使用-Otime),其他的常量将使用一个标准的乘法序列来完成 例如:实时除法程序使用CLZ指令

18、只有V5te体系结构才有效。用下面的办法来选择C-#pragma import _use_realtime_divisionAssembler-IMPORT _use_realtime_division,div10 MOV r1,r0 LDR r0,=0 xCCCCCCCD UMULL r2,r1,r0,r1 MOV r0,r1,LSR#3 MOV pc,lr,unsigned div10(unsigned c)return(c/10);,余数 模算法,余数的操作符%,通常使用模算法如果这个值的模不是2的n次幂,它将花费大量的时间和代码空间避免这种情况发生的办法使用if()作状态检查比如说:c

19、ount的范围是0到59count=(count+1)%60;用下面的句子代替if(+count=60)count=0;,modulo ADD r1,r0,#1 MOV r0,#0 x3c BL _rt_udiv MOV r0,r1,test_and_reset ADD r0,r0,#1 CMP r0,#0 x3c MOVCS r0,#0,这个代码用“-O1-Ospace”编译,浮点,软件浮点库(fplib)默认:-fpu softvfp(or softfpa)浮点协处理器VFP(ARM10 and ARM9)-fpu vfp(or vfpv1 or vfpv2)FPA(eg ARM7 500

20、fe)-now obsolete-fpu fpa软件浮点仿真(FPE)通过未定义的异常来捕获协处理器指令VFP(and FPA)实际上是硬件协处理器和仿真的混合要求支持代码去实现混合运算在AFS 1.3 和以后的版本里有VFP的 支持代码,在ADS的FPA里.在thumb代码使用fp处,vfp系统用-fpu softvfp+vfp编译使用-auto_float_constants 预防常量被处理为双精度类型,关闭警告用-Wk.,Example.,float foo(float num1,float num2)float temp,temp2;temp=num1+num2;temp2=num2*

21、num2;return temp2-temp;,Floating point examples,Agenda,ARM 编译器优化C/C+和汇编混合模式编程使用ARM编译器编码局部和全局数据,变量类型,全局和静态变量保留在RAM里需使用loads/stores访问外部存储器局部变量通常放在寄存器中,用来快速且高效的处理如果编译器的寄存器分配算法认为超过现有的寄存器数量,将把变量压入栈中对局部变量,用 word-sized(int)代替 halfword 和 byte:为了确保不受其他条件的影响,可特别指定使用32-bit寄存器变量.,int wordsize(int a)wordsize 0 x

22、000000:MOV r0,r0,LSL#1 return(a*2);0 x000004:MOV pc,lrshort halfsize(short b)halfsize 0 x000008:MOV r0,r0,LSL#17 return(b*2);0 x00000c:MOV r0,r0,ASR#16 0 x000010:MOV pc,lrchar bytesize(char c)bytesize 0 x000014:MOV r0,r0,LSL#25 return(c*2);0 x000018:MOV r0,r0,LSR#24 0 x00001c:MOV pc,lr,变量大小,堆栈的用法,C/

23、C+代码的堆栈使用,堆栈用来保留:子程序的返回地址溢出的局部变量局部数组和结构体注意:函数越小越好:(更少的变量,更少的溢出);更少数量的live变量(比如:函数里每个点保存的有用的数据)避免使用大的局部结构体或数组(使用malloc/free代替)避免递归,堆栈使用估计,链接使用-callgraph显示静态堆栈的开销(html文件).编译时使用软件堆栈检查-apcs/swst在栈结束点设置 watchpoint测试堆栈定义大的栈填充某个值,看覆盖了多少,从而判定栈的使用情况ARMulator映射文件拒绝访问栈下面的区域,栈溢出将导致一个data abort异常stackuse.cARMula

24、tor模式,跟踪堆栈的大小,用ARMulator的统计来输出报告,当要对堆栈使用情况进行估计时,使用worst case,全局数据布局,char one;short two;char three;int four;,char,short,char,e.g.声明的数据,Declared alignment12 bytes(4 bytes of padding),Optimal alignment8 bytes(Zero bytes of padding),ADS 1.1+将自动用此风格排序,short,全局数据保存在存储器里,不是寄存器需要load/store指令来访问用物理尺寸的边界对齐ADS

25、 1.2 会优化在一个模块里的全局数据的布局用-Ono_data_reorder 将关闭排序,不对齐访问,ARM硬件需要在自然尺寸的边界访问内存Word访问在word尺寸Halfword访问在halfword尺寸Byte访问在byte尺寸不对齐访问遗留代码特定协议需要必须告诉编译器,让它产生适当的指令序列使用 _packed 属性可能导致多字节访问代替单字节访问用LDM指令的结果有2 字,转变为生成单字不对齐数据的访问所产生的意外的结果取决于指令的使用将是不可预知的,指针的对齐,必须非常小心指针的对齐可能导致程序的失败,#include int*a=(int*)0 x1000;int*b=(i

26、nt*)0 x2000;char*c=(char*)0 x3001;_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,0 x58LDR r1,r4,#0LDR r0,r4,#4LDMIA r1,r2,r3,r12STMIA r0,r2,r3,r12LDR r0,r4,#8LDR r1,r4,#0MOV r2,#0 xcBL _rt_memcpyLDR r

27、0,r4,#8STR r0,r4,#4LDR r1,r4,#0LDMIA r1,r2,r3,r12STMIA r0,r2,r3,r12LDR r0,r4,#8LDR r1,0 x5cMOV r2,#0 xcSTR r0,r1,#0LDR r1,r4,#0BL _rt_memcpyLDMFD r13!,r4,pc,结构的打包,在结构里定义打包的元素代替结构的打包他将帮助减小访问输出的结构的开销ADS FAQ 入口:Aligned v.unaligned accesses and use of _packed,_packed struct mystruct int aligned_i;short

28、aligned_s;int unaligned_i;extern struct mystruct S;,short,int,U_int,U_int,_packed限定的数据为1字节对齐不实现字节对齐调整很高的访问代价,不会节省存储空间,优化的指针基地址,extern int a;extern int b;void foo(int x,int y)a=x;b=y;,优化外部全局指针,如果全局数据放在结构体里,每个元素的访问将自动的在基指针上偏移在结构体里的元素将按大小的边界对齐编译器不对结构体重新排列把数据放在多个逻辑结构体内,代替一个大的结构#define 将对主应用代码的改变隐藏起来#def

29、ine value mystruct.value,Example.,外部全局变量,extern int a;extern int b;int main(void)return a+b;,int a;int b;,mainLDR r0,0 x000080c0000080acLDR r1,0 x000080c4000080b0LDR r0,r0,#0000080b4LDR r1,r1,#0000080b8ADD r0,r0,r1000080bcMOV pc,lr000080c0DCD 0 x000083d4000080c4DCD 0 x000083d8,data.c,code.c,Assemble

30、r output,测验,1)默认的优化级别是什么?2)给tail-call优化有什么好处3)在函数调用时,管理寄存器用法的标准的名字是什么?4)在参数传递时,被推荐的最大的量是多少?5)为什么在arm里要尽可能避免使用除法?6)_packed的效果是什么?,参考,需要更多的信息,请看:ADS 1.2 Compilers and Libraries GuideSection 2:C and C+CompilersSection 3:ARM Compiler ReferenceADS 1.2 Developer GuideChapter 4:Mixing C,C+and Assembly LanguageApplication Note 34,Writing Efficient CApplication Note 36,Declaring Global Data in C,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号