首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

ARM下高效C编程

ARM下高效C编程

通过一定的风格来编写C程序,可以帮助C编译器生成执行速度更快的ARM代码。下面就是一些与性能相关的关键点:

       1、对局部变量、函数参数和返回值要使用signedunsigned int类型。这样可以避免类型转换,而且可高效地使用ARM32位数据操作指令。

       2、最高效的循环体形式是减计数到零(counts down to zero)的do-while循环。

       3、展开重要的循环来减少循环的开销。

       4、不要依赖编译器来优化掉重复的存储器访问。指针别名会阻止编译器的这种优化。

       5、尽可能把函数参数的个数限制在4个以内。如果函数参数都存放在寄存器内,那么函数调用就会快得多。

       6、按元素尺寸从小到大排列的方法来安排结构体,特别是在thumb模式下编译。

       7、不要使用位域,可以用掩码和逻辑操作来替代。

       8、避免除法,可以用倒数的乘法来替代。

       9、避免边界不对齐的数据。如果数据有可能边界不对齐,那么就要使用char *指针类型来访问。

       10、在C编译器中使用内嵌汇编可以利用到C编译器本来不支持的指令或优化。


一、
数据类型使用上的优化

1、局部变量

一个char类型的数据比int类型的数据占用更小的寄存器空间或者更小的ARM堆栈空间。这两种设想对于ARM来说,都是错误的。所有的ARM寄存器都是32位的,所有的堆栈入口至少是32位的。当我们执行i++,要利用当i=255后,i++=0这个条件时,可以把它定义为char类型。

       2、函数参数


尽管宽和窄的函数调用规则各有其优点,但charshort类型的函数参数和返回值都会产生额外的开销,导致性能的下降,并增加了代码尺寸。所以,即使是传输一个8位的数据,函数参数和返回值使用int类型也会更有效。

       3、总结

              1)对于存放在寄存器中的局部变量,除了8位或16位的算术模运算外,尽量不要使用charshort类型,而要使用有符号或无符号int类型。除法运算时使用无符号数执行速度更快。

              2)对于存放在主存储器中的数组和全局变量,在满足数据大小的前提下,应尽可能使用小尺寸的数据类型,这样可以节省存储空间。ARMv4体系结构可以有效地装载和存储所有宽度的数据,并可以使用递增数组指针来有效地访问数组。对于short类型数组,要避免使用数组基地址的偏移量,因为LDRH指令不支持偏移寻址。

              3)通过读取数组或全局变量并赋给不同类型的局部变量时,或者把局部变量写入不同类型的数组或者全局变量时,要进行显式数据类型转换。这种转换使编译器可以明确、快速地处理,把存储器中数据宽度比较窄的数据类型扩展,并赋给寄存器中较宽的类型。

              4)由于隐式或者显式的数据类型转换通常会有额外的指令周期开销,所以在表达式中应尽量避免使用。Loadstore指令一般不会产生额外的转换开销,因为loadstore指令是自动完成数据类型转换的。

              5)对于函数参数和返回值应尽量避免使用charshort类型。即使参数范围比较小,也应该使用int类型,以防止编译器做不必要的类型转换。

二、C循环结构

ARM上,一个循环其实只要2条指令就足够了:

一条减法指令,进行循环减法计数,同时设置结果的条件标志;

一条条件分支指令。

这里的关键是,循环的终止条件应为减计数到零,而不是计数增加到某个特定的限制值。由于减计数结构已存储在条件标志里,与零比较的指令就可以省略了。由于不用i作为数组的下标索引,采用减计数就没有任何问题了。

总而言之,无论对于有符号的循环计数值,都应使用i=0作为循环的结束条件。对有符号数i,这比使用条件i>0少了一条指令。

总结:

1 使用减计数到零的循环结构,这样编译器就不需要分配一个寄存器来保存循环终止值,而且与0比较的指令也可以省略。

2 使用无符号的循环计数值,循环继续的条件为i!=0而不是i>0,这样可以保证循环开销只有两条指令。

3 如果事先知道循环体至少会执行一次,那么使用do-while循环要比for循环要好,这样可以使编译器省去检查循环计数值是否为零的步骤。

4 展开重要的循环体可降低循环开销,但不要过度展开,如果循环的开销对整个程序来说占的比例很小,那么循环展开反而会增加代码量并降低cache的性能。

5 尽量使数组的大小是48的倍数,这样可以容易的以248次等多种选择展开循环,而不需要担心剩余数组元素的问题。

三、

返回列表