简单的ADD / ADC ARM assemlby失败
我有(以下)相同代码的以下C和ASM版本.它的作用是加载2个128位整数,每个由2个64位整数表示,寄存器(前4 *低32位,然后4 *高32位)和ADD / ADC.它足够简单,而ARM / ST手册实际上给出了96bit(3个ADD / ADC)的相同示例.
对于简单调用,两个版本都有效(重复添加(1 <<< x)或1..x).但是对于较长的测试套件,ARM组件会出现故障(电路板挂起). ATM我没有能力捕获/调试那个并且不能使用任何printf()或者喜欢找到测试失败,这无论如何都是无关紧要的,因为ASM版本中必定存在一些基本错误,因为C版本按预期工作. 我没有得到它,它很简单,非常接近C汇编输出(没有分支).我尝试了“内存”约束(不应该需要),我尝试在寄存器中保存低位和高位64位之间的进位,然后使用ADD(C).W,对齐,使用两个LDR / STR代替LDRD / STRD等.我假设电路板出现故障,因为某些附加设备出错并导致除以0或类似的情况. 我真的只是寻找最快的添加方式,而不是专门修复代码.遗憾的是你必须使用常量寄存器名称,因为没有约束来指定rX和rX 1.此外,使用与GCC一样多的寄存器是不可能的,因为它们在编译期间会耗尽它们. typedef struct I128 { int64_t high; uint64_t low; } I128; I128 I128add(I128 a,const I128 b) { #if defined(USEASM) && defined(ARMx) __asm( "LDRD %%r2,%%r3,%[alo]n" "LDRD %%r4,%%r5,%[blo]n" "ADDS %%r2,%%r2,%%r4n" "ADCS %%r3,%%r5n" "STRD %%r2,%[alo]n" "LDRD %%r2,%[ahi]n" "LDRD %%r4,%[bhi]n" "ADCS %%r2,%%r4n" "ADC %%r3,%[ahi]n" : [alo] "+m" (a.low),[ahi] "+m" (a.high) : [blo] "m" (b.low),[bhi] "m" (b.high) : "r2","r3","r4","r5","cc" ); return a; #else // faster to use temp than saving low and adding to a directly I128 r = {a.high + b.high,a.low + b.low}; // check for overflow of low 64 bits,add carry to high // avoid conditionals //r.high += r.low < a.low || r.low < b.low; // actually gcc produces faster code with conditionals if(r.low < a.low || r.low < b.low) ++r.high; return r; } 使用“armv7m-none-eabi-gcc-4.7.2 -O3 -ggdb -fomit-frame-pointer -falign-functions = 16 -std = gnu99 -march = armv7e-m”的GCC C版本: b082 sub sp,#8 e92d 0ff0 stmdb sp!,{r4,r5,r6,r7,r8,r9,sl,fp} a908 add r1,sp,#32 e881 000c stmia.w r1,{r2,r3} e9dd 890e ldrd r8,[sp,#56] ; 0x38 e9dd 670a ldrd r6,#40] ; 0x28 e9dd 2308 ldrd r2,r3,#32] e9dd 450c ldrd r4,#48] ; 0x30 eb16 0a08 adds.w sl,r8 eb47 0b09 adc.w fp,r9 1912 adds r2,r2,r4 eb43 0305 adc.w r3,r5 45bb cmp fp,r7 bf08 it eq 45b2 cmpeq sl,r6 d303 bcc.n 8012c9a <I128add+0x3a> 45cb cmp fp,r9 bf08 it eq 45c2 cmpeq sl,r8 d204 bcs.n 8012ca4 <I128add+0x44> 2401 movs r4,#1 2500 movs r5,#0 1912 adds r2,r5 e9c0 2300 strd r2,[r0] e9c0 ab02 strd sl,fp,[r0,#8] e8bd 0ff0 ldmia.w sp!,fp} b002 add sp,#8 4770 bx lr 我的ASM版本失败: b082 sub sp,#8 b430 push {r4,r5} a902 add r1,#8 e881 000c stmia.w r1,r3} e9dd 2304 ldrd r2,#16] e9dd 4508 ldrd r4,#32] 1912 adds r2,r4 416b adcs r3,r5 e9cd 2304 strd r2,#16] e9dd 2302 ldrd r2,#8] e9dd 4506 ldrd r4,#24] 4162 adcs r2,r4 eb43 0305 adc.w r3,r5 e9cd 2302 strd r2,#8] 4604 mov r4,r0 c90f ldmia r1,{r0,r1,r3} e884 000f stmia.w r4,r3} 4620 mov r0,r4 bc30 pop {r4,r5} b002 add sp,#8 4770 bx lr 解决方法
我没有从您的代码中获取挂起,但它也不起作用,不知道为什么.但是很容易修补编译器生成的代码来处理进位:
I128 I128add(I128 a,const I128 b) { I128 r = {a.high + b.high,a.low + b.low}; return r; } 变 000001e4 <I128add>: 1e4: b082 sub sp,#8 1e6: b4f0 push {r4,r7} 1e8: e9dd 4506 ldrd r4,#24] 1ec: a904 add r1,#16 1ee: e881 000c stmia.w r1,r3} 1f2: e9dd 230a ldrd r2,#40] ; 0x28 1f6: 1912 adds r2,r4 1f8: eb43 0305 adc.w r3,r5 1fc: e9dd 6704 ldrd r6,#16] 200: e9dd 4508 ldrd r4,#32] 204: 1936 adds r6,r4 206: eb47 0705 adc.w r7,r5 20a: e9c0 6700 strd r6,[r0] 20e: e9c0 2302 strd r2,#8] 212: bcf0 pop {r4,r7} 214: b002 add sp,#8 216: 4770 bx lr 修正了补充 .thumb_func .globl test2 test2: sub sp,#8 push {r4,r7} ldrd r4,#24] add r1,#16 stmia r1,r3} ldrd r2,#40] add r2,r4 adc r3,r5 ldrd r6,#16] ldrd r4,#32] adc r6,r4 adc r7,r5 strd r6,[r0] strd r2,#8] pop {r4,r7} add sp,#8 bx lr 最后结果 00000024 <test2>: 24: b082 sub sp,#8 26: b4f0 push {r4,r7} 28: e9dd 4506 ldrd r4,#24] 2c: a904 add r1,#16 2e: c10c stmia r1!,r3} 30: e9dd 230a ldrd r2,#40] ; 0x28 34: 1912 adds r2,r4 36: 416b adcs r3,r5 38: e9dd 6704 ldrd r6,#16] 3c: e9dd 4508 ldrd r4,#32] 40: 4166 adcs r6,r4 42: 416f adcs r7,r5 44: e9c0 6700 strd r6,[r0] 48: e9c0 2302 strd r2,#8] 4c: bcf0 pop {r4,r7} 4e: b002 add sp,#8 50: 4770 bx lr 注意thumb2指令的数量较少,除非你在具有thumb2支持的cortex-A上,那些来自flash(cortex-m)的提取(可能)很慢.我看到你正在尝试保存另外两个寄存器的推送和弹出,但是你花费了更多的时间.你可以采取上述方法,仍然重新安排加载和存储,并保存这两个寄存器. 迄今为止的最小测试. printfs显示上面的单词添加,我没有看到你的代码.我仍然试图解开调用约定(请为我们更多地记录您的代码),看起来r0由调用者准备放置结果,rest在堆栈上.我正在使用stellaris启动板(cortex-m4). (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |