搜索
bottom↓
回复: 26

难道ARM一定要用 INT32 类型才是最高效的吗??

[复制链接]

出0入0汤圆

发表于 2010-12-1 17:19:48 | 显示全部楼层 |阅读模式
1 函数局部变量的数据类型
  局部变量包括函数内局部变量、函数参数、函数返回值。由于ARM数据操作都是32位,即使数据本身只需要8位或16位,对于这三类局部变量也应尽可能使用32位的数据类型int或long,以提高代码执行效率。下面以简单求和函数为例进行分析。
  函数add1计算包含10个字的数组array的累加和,add2与add1功能相同,只是将函数add1的参数array类型改为16位的short,函数内局部变量i类型改为8位的char,sum改为16位的short。add1、add2的C源代码如下:
int add1(int *array){
  unsigned int i;
  int sum=0;
  for(i=0;i<10;i++)
  sum=sum+array;
  return sum;
}
short add2(short *array){
  char i;
  short sum=0;
  for(i=0;i<10;i++)
  sum= sum+array;
  return sum;
}
  add1经编译产生的汇编代码:
add1
mov r2,r0
mov r0,#0
mov r1,#0
add1_loop
ldr r3,[r2,r1,lsl #2]
add r1,r1,#1
cmp r1,#0x0a
add r0,r3,r0
bcc add1_loop
mov pc,r14
add2经编译产生的汇编代码:
add2
mov r2,r0
mov r0,#0
mov r1,#0
add2_loop
add r3,[r2,r1,lsl #1];增加语句①
ldrh r3,[r3,#0]
add r1,r1,#1
and r1,r1,0xff;增加语句②
cmp r1,#0x0a
add r0,r3,r0
bcc add2_loop
mov r0,r0,lsl #16;增加语句③
mov r0,r0,asr #16;增加语句④
mov pc,r14
  比较add1和add2两个函数的汇编代码,可以发现add2_loop循环比add1_loop循环增加了4条语句。
  语句①:函数add2中变量sum为16位short类型,ARM指令中ldrh指令不支持移位地址偏移,因此增加add指令计算数组下标地址。
  语句②:由于函数add2中循环变量i为8位的char类型,而ARM处理器的寄存器为32位,此语句用于处理循环变量累加过程中引起的溢出问题。即:当i累加到255时,再加1应该为0,而不是256。
  语句③、④:函数add2中返回结果sum为short类型,在返回前需将32位寄存器的前16位用符号位填充,即转换为16位short类型。

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

 楼主| 发表于 2010-12-1 17:20:27 | 显示全部楼层
我咋不敢苟同呢?

出0入0汤圆

 楼主| 发表于 2010-12-1 17:22:20 | 显示全部楼层
按照作者的逻辑,如果除去空间占用问题,都用32位的变量了??

出0入0汤圆

 楼主| 发表于 2010-12-1 17:56:09 | 显示全部楼层
这方面有研究的讨论讨论啊

出0入0汤圆

发表于 2010-12-1 19:33:12 | 显示全部楼层
新的ARM--M3好像没这个问题了

出0入0汤圆

发表于 2010-12-1 19:34:02 | 显示全部楼层
应该是的

出0入24汤圆

发表于 2010-12-1 19:39:53 | 显示全部楼层
cortex-M3也有这个问题
使用8位的数据,编译器在编译的时候总是插入字节扩展指令;
使用16位数据,如果是无符号数,则没有影响;如果是有符号数,那么会插入半字扩展指令;

出0入0汤圆

发表于 2010-12-1 19:58:23 | 显示全部楼层
确实,M3多了三条指令,

    7          int add1(int *array)
      8          {
      9            unsigned int i;
     10            int sum=0;
   \                     add1:
   \   00000000   0021               MOVS     R1,#+0
     11            for(i=0;i<10;i++)
   \   00000002   0022               MOVS     R2,#+0
   \   00000004   03E0               B.N      ??add1_0
     12              sum=sum+array;
   \                     ??add1_1:
   \   00000006   50F82230           LDR      R3,[R0, R2, LSL #+2]
   \   0000000A   5918               ADDS     R1,R3,R1
   \   0000000C   521C               ADDS     R2,R2,#+1
   \                     ??add1_0:
   \   0000000E   0A2A               CMP      R2,#+10
   \   00000010   F9D3               BCC.N    ??add1_1
     13            return sum;
   \   00000012   0800               MOVS     R0,R1
   \   00000014   7047               BX       LR               ;; return
     14         
     15          }
     16         

   \                                 In section .text, align 2, keep-with-next
     17          short add2(short *array)
     18          {
     19           char i;
     20           short sum=0;
   \                     add2:
   \   00000000   0021               MOVS     R1,#+0
     21           for(i=0;i<10;i++)
   \   00000002   0022               MOVS     R2,#+0
   \   00000004   04E0               B.N      ??add2_0
     22             sum=sum+array;
   \                     ??add2_1:
   \   00000006   D2B2               UXTB     R2,R2            ;; ZeroExt  R2,R2,#+24,#+24
   \   00000008   30F81230           LDRH     R3,[R0, R2, LSL #+1]
   \   0000000C   5918               ADDS     R1,R3,R1
   \   0000000E   521C               ADDS     R2,R2,#+1
   \                     ??add2_0:
   \   00000010   D2B2               UXTB     R2,R2            ;; ZeroExt  R2,R2,#+24,#+24
   \   00000012   0A2A               CMP      R2,#+10
   \   00000014   F7D3               BCC.N    ??add2_1
     23           return sum;
   \   00000016   0800               MOVS     R0,R1
   \   00000018   00B2               SXTH     R0,R0            ;; SignExt  R0,R0,#+16,#+16
   \   0000001A   7047               BX       LR               ;; return
     24          }

出0入0汤圆

发表于 2010-12-1 20:17:33 | 显示全部楼层
这个问题对CM3依然存在的,我以前曾经测试过,开始我的代码是由avr移植过来的,有大量的8位变量,改为32位后代码尺寸会减小。

出0入0汤圆

发表于 2010-12-1 21:11:05 | 显示全部楼层
没有深揪过,是不是说几位的芯片就要用几位的数据类型才高效

出0入0汤圆

 楼主| 发表于 2010-12-1 21:16:31 | 显示全部楼层
按照这个逻辑 PC桌面应用 程序都应该用long型变量了??

出0入0汤圆

发表于 2010-12-1 21:31:08 | 显示全部楼层
b回复【10楼】51FLY  
按照这个逻辑 pc桌面应用 程序都应该用long型变量了??
-----------------------------------------------------------------------

就算法而言,可能真是这样呢。不过对于巨无霸的PC而言,大多数程序不在乎这点代码尺寸和速度差异,但是对于单片机这个小家伙,flash空间和处理速度都有限,这个有时候还真的考虑考虑。不过,这个可能和不同编译器的优化也有关系,有些聪明的编译器应该能理解程序代码的意图,少做点变换无用功,但我用的gcc目前看来还需要更聪明些。

出0入0汤圆

发表于 2010-12-1 21:36:30 | 显示全部楼层
嘿嘿~~有用啊

出0入0汤圆

发表于 2010-12-1 21:57:13 | 显示全部楼层
两个方面看:

1、硬件架构上:
因为ARM绝大多数指令对32Bit寄存器进行操作,基本上无16/8Bit的部分寄存器操作指令。(这里不考虑SIMD,64Bit操作数等等少数派指令)。
所以无论int8/int16,读取之后进行符号/无符号扩展,使用int32的中间变量进行计算,最后处理回int8/in16,都会在中间过程中获得好处。如果中间使用int8/16,那么在每次计算之后,多少都会存在约束结果范围的操作,这写就是多出来的指令了。

2,C标准上:
C标准有一些整型计算是隐含类型提升的,目标是int/最大变量类型,得到计算结果后再转换回去。如果在最大类型上进行计算,就少了转换的操作。这点其实和硬件结构有对应关系;而且,有的部分和编译器/硬件实现相关。(就是说,16Bit处理器非要跑int32,那不一定能有啥好)。


对X86而言,也是类似的。
只不过,X86指令集能针对寄存器的不同部分操作,比如对通用寄存器,可以支持AL/AH/AX/EAX/RAX这些不同位宽的访问,不像ARM,一个R0就是32bit。如果用SSE的XMM,那么指令直接包含对8/16/32/64的整数操作编码。
指令集具备了加工int8/16/32的特定指令,此时计算就在遵循标准的前提下,直接使用对应的指令完成。不用绕一个圈。
C99标准的stdint.h中给出了int_fastN_t这样的变量类型,有兴趣的可以看看。

出0入0汤圆

发表于 2010-12-1 23:49:32 | 显示全部楼层
学习!

出0入0汤圆

发表于 2010-12-2 02:00:31 | 显示全部楼层
AVR32就多出一条指令

      3          int add1(int *array)
      4          {
      5            unsigned int i;
      6            int sum=0;
   \                     add1:
   \   000000 300B          MOV       R11,0x0
      7            for(i=0;i<10;i++)
   \   000002 300A          MOV       R10,0x0
      8              sum=sum+array;
   \                     ??add1_0:
   \   000004 F80A0329      LD.w      R9,R12[R10<<0x2]
   \   000008 120B          ADD       R11,R9
   \   00000A 2FFA          SUB       R10,-0x1
   \   00000C 58AA          CP.w      R10,0xa
   \   00000E CFB3          BRCS      ??add1_0:C
      9            return sum;
   \   000010 5EFB          RET       R11
     10         
     11          }
     12         

   \                                 In  segment CODE32, align 4
     13          short add2(short *array)
     14          {
     15           char i;
     16           short sum=0;
   \                     add2:
   \   000000 300A          MOV       R10,0x0
     17           for(i=0;i<10;i++)
   \   000002 3009          MOV       R9,0x0
     18             sum=sum+array;
   \                     ??add2_0:
   \   000004 F809041B      LD.sh     R11,R12[R9<<0x1]
   \   000008 160A          ADD       R10,R11
   \   00000A 5C8A          CASTS.h   R10
   \   00000C 2FF9          SUB       R9,-0x1
   \   00000E 58A9          CP.w      R9,0xa
   \   000010 CFA5          BRLT      ??add2_0:C
     19           return sum;
   \   000012 5EFA          RET       R10
     20          }

出0入0汤圆

发表于 2010-12-2 09:03:52 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-2 09:58:33 | 显示全部楼层
回复【13楼】dr2001  
-----------------------------------------------------------------------
看了很多帖子,dr2001兄的回复每次都让人受益匪浅啊!



回复【楼主位】51FLY  
-----------------------------------------------------------------------
这个问题在《ARM嵌入式系统开发-软件设计与优化》这本书的第五章有详细的说明,如果想了解的话可以去看看。
这本书在本站可以下载到。

出0入0汤圆

发表于 2010-12-2 09:59:49 | 显示全部楼层
是的

出0入0汤圆

 楼主| 发表于 2010-12-2 12:35:44 | 显示全部楼层
赞叹 受益匪浅

出0入0汤圆

 楼主| 发表于 2010-12-3 17:24:17 | 显示全部楼层

(原文件名:优化.JPG)

出0入0汤圆

 楼主| 发表于 2010-12-3 17:26:28 | 显示全部楼层
最后的结论

出0入0汤圆

发表于 2010-12-3 19:09:37 | 显示全部楼层
空间和时间的平衡

出0入0汤圆

发表于 2010-12-4 08:26:24 | 显示全部楼层
搭个车问下: ARM硬件带不带符号处理, UINT 和INT效率一样么?

出0入0汤圆

发表于 2010-12-4 08:31:45 | 显示全部楼层
严重关注,ARM7,9这个理解,CM3也这样?编译器问题?要看汇编指令了

出0入0汤圆

发表于 2010-12-4 10:36:19 | 显示全部楼层
回复【21楼】51FLY  
-----------------------------------------------------------------------

LDRH这个系列指令的描述不确切(32Bit ARM指令)。LDRH系列因为编址空间不足,导致偏移量从12Bit减少到8Bit,并且取消了偏移地址REG移位。具体请见ARM指令集手册。


回复【23楼】first blood  
-----------------------------------------------------------------------

“平衡”含有双方折中的含义;对仅在REG中进行的计算,可能出现双赢的结果。。。不用“平衡”。这么说对这个情景略有不足。


回复【24楼】tomhe666  天煞孤星
-----------------------------------------------------------------------

对加减,比较大小等基本操作,几乎所有处理器都是等速度支持有/无符号操作。
对乘除法,有符号的计算可能略慢,也可能等速;通常是要支持则同时支持有/无符号,最好查手册确认。
特殊的整数计算(饱和加减etc),SIMD等等,有/无符号支持谁不一定,必须查手册。


回复【25楼】sufeila  
-----------------------------------------------------------------------

这主要是ISA问题。
和编译器有关,但编译器不是决定性的,因为编译器不了解用户的实际需求,并且需要遵循标准的规定。

ARM体系到目前ISA没有大变化,因此结果就不会有大变化。
具有SIMD的Core,可以用SIMD的标量实现部分解决此问题,但估计编译器不一定会用,而且计算速度未必会快。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-20 21:28

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表