我有以下C和ASM版本的代码(据说是相同的代码)。它的作用是将由两个64位整数表示的2个128位整数加载到寄存器中(先是4*低32位,然后是4*高32位),并进行
对于简单调用,两个版本都可以工作(重复添加
我不明白,它非常简单,非常接近C汇编输出(sans branching)。我尝试了“内存”约束条件(不应该需要),尝试在低64位和高64位之间保存进位并稍后加上,使用
我真的只是想寻找最快的方法来进行加法运算,而不仅仅是修复那段代码。很遗憾,您必须使用常量寄存器名称,因为没有约束规定如何指定
ADD
/ADC
运算。这段代码非常简单,ARM/ST手册实际上给出了相同的96位示例(使用3个ADD
/ADC
)。对于简单调用,两个版本都可以工作(重复添加
(1 << x++)
或1..x)。但是对于更长的测试套件,ARM汇编失败(板子挂起)。目前我没有能力陷阱/调试它,并且不能使用任何printf()
之类的函数来找到测试失败的原因,而这些也是无关紧要的,因为必须存在某些基本故障在ASM版本中,而C版本按预期工作。我不明白,它非常简单,非常接近C汇编输出(sans branching)。我尝试了“内存”约束条件(不应该需要),尝试在低64位和高64位之间保存进位并稍后加上,使用
ADD(C).W
,对齐,使用两个LDR
/STR
而不是LDRD
/STRD
等。我认为板子因为某些加法出错导致,可能会出现除以0之类的结果。以下是GCC ASM版本的代码,使用类似的基本技术,因此我不明白问题所在。我真的只是想寻找最快的方法来进行加法运算,而不仅仅是修复那段代码。很遗憾,您必须使用常量寄存器名称,因为没有约束规定如何指定
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, %%r4\n"
"ADCS %%r3, %%r3, %%r5\n"
"STRD %%r2, %%r3, %[alo]\n"
"LDRD %%r2, %%r3, %[ahi]\n"
"LDRD %%r4, %%r5, %[bhi]\n"
"ADCS %%r2, %%r2, %%r4\n"
"ADC %%r3, %%r3, %%r5\n"
"STRD %%r2, %%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, r9, [sp, #56] ; 0x38
e9dd 670a ldrd r6, r7, [sp, #40] ; 0x28
e9dd 2308 ldrd r2, r3, [sp, #32]
e9dd 450c ldrd r4, r5, [sp, #48] ; 0x30
eb16 0a08 adds.w sl, r6, r8
eb47 0b09 adc.w fp, r7, r9
1912 adds r2, r2, r4
eb43 0305 adc.w r3, 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, r2, r4
eb43 0305 adc.w r3, r3, r5
e9c0 2300 strd r2, r3, [r0]
e9c0 ab02 strd sl, fp, [r0, #8]
e8bd 0ff0 ldmia.w sp!, {r4, r5, r6, r7, r8, r9, sl, fp}
b002 add sp, #8
4770 bx lr
我失败的ASM版本:
b082 sub sp, #8
b430 push {r4, r5}
a902 add r1, sp, #8
e881 000c stmia.w r1, {r2, r3}
e9dd 2304 ldrd r2, r3, [sp, #16]
e9dd 4508 ldrd r4, r5, [sp, #32]
1912 adds r2, r2, r4
416b adcs r3, r5
e9cd 2304 strd r2, r3, [sp, #16]
e9dd 2302 ldrd r2, r3, [sp, #8]
e9dd 4506 ldrd r4, r5, [sp, #24]
4162 adcs r2, r4
eb43 0305 adc.w r3, r3, r5
e9cd 2302 strd r2, r3, [sp, #8]
4604 mov r4, r0
c90f ldmia r1, {r0, r1, r2, r3}
e884 000f stmia.w r4, {r0, r1, r2, r3}
4620 mov r0, r4
bc30 pop {r4, r5}
b002 add sp, #8
4770 bx lr