在gcc中内联程序集时,我发现自己经常需要添加空的asm块,以便在早期的块中保持变量存活,例如:
asm("rcr $1,%[borrow];"
"movq 0(%[b_],%[i],8),%%rax;"
"adcq %%rax,0(%[r_top],%[i],8);"
"rcl $1,%[borrow];"
: [borrow]"+r"(borrow)
: [i]"r"(i),[b_]"r"(b_.data),[r_top]"r"(r_top.data)
: "%rax","%rdx");
asm("" : : "r"(borrow) : ); // work-around to keep borrow alive ...
另一个奇怪的例子是,下面的代码在没有优化的情况下工作得很好,但是-O3就是seg-faults:
ulong carry = 0,hi = 0,qh = s.data[1],ql = s.data[0];
asm("movq 0(%[b]),%%rax;"
"mulq %[ql];"
"movq %%rax,0(%[sb]);"
"movq %%rdx,%[hi];"
: [hi]"=r"(hi)
: [ql]"r"(ql),[b]"r"(b.data),[sb]"r"(sb.data)
: "%rax","%rdx","memory");
for (long i = 1; i < b.size; i++)
{
asm("movq 0(%[b],%[i],8),%%rax;"
"mulq %[ql];"
"xorq %%r10,%%r10;"
"addq %%rax,%[hi];"
"adcq %%rdx,%[carry];"
"adcq $0,%%r10;"
"movq -8(%[b],%[i],8),%%rax;"
"mulq %[qh];"
"addq %%rax,%[hi];"
"adcq %%rdx,%[carry];"
"adcq $0,%%r10;"
"movq %[hi],0(%[sb],%[i],8);"
"movq %[carry],%[hi];"
"movq %%r10,%[carry];"
: [carry]"+r"(carry),[hi]"+r"(hi)
: [i]"r"(i),[ql]"r"(ql),[qh]"r"(qh),[b]"r"(b.data),[sb]"r"(sb.data)
: "%rax","%rdx","%r10","memory");
}
asm("movq -8(%[b],%[i],8),%%rax;"
"mulq %[qh];"
"addq %%rax,%[hi];"
"adcq %%rdx,%[carry];"
"movq %[hi],0(%[sb],%[i],8);"
"movq %[carry],8(%[sb],%[i],8);"
: [hi]"+r"(hi),[carry]"+r"(carry)
: [i]"r"(long(b.size)),[qh]"r"(qh),[b]"r"(b.data),[sb]"r"(sb.data)
: "%rax","%rdx","memory");
我认为这与它使用如此多的寄存器这一事实有关。有没有我在这里缺少的东西,或者注册分配是否真的与gcc内联汇编错误?
答案 0 :(得分:2)
你缺少的是GCC的优化器会假设asm
块的唯一副作用是改变输出操作数。如果以后没有使用这些操作数,则可以假定asm
块不必要,可以删除。
e.g。在您的第一个示例中,如果随后未使用borrow
,则可以自由地假设根本不包含asm
块,因为它唯一的副作用是更新变量从未再次使用过。在第二个示例中,如果在您显示的代码之后未再次使用hi
和carry
,则可能会推断它几乎可以删除所有内容!
您可以通过编写asm volatile(...)
而不是asm(...)
来告知GCC不应删除您的内联汇编块。
有关详细信息,请参阅http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html(大约在页面的中间部分)。