Странное поведение с встроенной сборкой gcc - PullRequest
1 голос
/ 20 февраля 2011

При вставке ассемблера в 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?

1 Ответ

2 голосов
/ 20 февраля 2011

Чего вам не хватает, так это того, что оптимизатор GCC будет предполагать, что единственным побочным эффектом блока asm является изменение выходных операндов. Если эти операнды впоследствии не используются, можно предположить, что блок asm не нужен и может быть удален.

например. в вашем первом примере, если borrow впоследствии не используется, можно предположить, что нет никакого смысла вообще включать блок asm, потому что единственным побочным эффектом является обновление переменной, которая никогда больше не используется , А во втором примере, если hi и carry больше не используются после кода, который вы показали, это, вероятно, будет означать, что он может удалить практически все!

Вы можете сказать GCC, что ваши встроенные блоки сборки не следует удалять, написав asm volatile(...) вместо asm(...).

Подробнее об этом см. http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html (примерно на полпути вниз по странице).

...