1

在 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 它会出现段错误:

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 内联汇编的寄存器分配真的有问题?

4

1 回答 1

2

您缺少的是 GCC 的优化器将假定asm块的唯一副作用是更改输出操作数。如果这些操作数随后没有被使用,它可以假定该asm块是不必要的并且可以被删除。

例如,在您的第一个示例中,如果borrow随后不使用,则可以自由假设根本没有包含该asm块的意义,因为它唯一的副作用是更新一个不再使用的变量。在第二个示例中,如果在您显示的代码之后再次使用hi并且carry没有再次使用,它可能会推断它可以删除几乎所有内容!

您可以告诉 GCC,您的内联汇编块不应该通过编写来删除,asm volatile(...)而不仅仅是asm(...).

有关这方面的更多详细信息,请参阅http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html(大约在页面的中间位置)。

于 2011-02-20T13:22:21.367 回答