Мовсбл рядом с рет хорош для производительности? - PullRequest
1 голос
/ 03 апреля 2019
char c;
int f()
{
    return c ^ 1;
}

gcc компилирует это в нечто вроде

movzbl  c(%rip), %eax
xorl    $1, %eax
movsbl  %al, %eax
ret

Это полезно из-за какой-то неупорядоченной или суперскалярной функции?

1 Ответ

2 голосов
/ 03 апреля 2019

Нет, это пропущенная оптимизация GCC ;что C может юридически быть в первую очередь для продления знака.Вы должны сообщить об этом в bugzilla GCC с ключевым словом «пропущенная оптимизация».

clang, ICC и MSVC ( на Godbolt ) скомпилировать его в ожидаемый

f:
        movsbl  c(%rip), %eax           # sign extend first
        xorl    $1, %eax
        retq

Даже попытка удержать GCC в этом коде с этим C не может заставить GCC сделать это:

int f() {
    int tmp = c;
    tmp ^= 1;
    return tmp;
}

Я предполагаю, что, возможно, GCC решит просто загрузить 1 байти продлите знак после вместо ранее.ИДК, почему он считает, что это хорошая идея.Но в любом случае, чтобы избежать ложной зависимости от старого значения RAX, необходимо какое-то расширение до 32-разрядного.

Запись C таким образом вводит ICC в эту пропущенную оптимизацию, но не MSVC или clang.Они все еще оптимизируют это для расширения знака в первую очередь, потому что они знают, что XOR не может изменить какие-либо старшие биты.

int extend_after() {
    char tmp = c^1;
    return tmp;
}

теперь ICC похож на GCC, но по какой-то причине знак расширяется до 64-бит:

extend_after:
        movzbl    c(%rip), %eax                                 #10.16
        xorl      $1, %eax                                      #10.18
        movsbq    %al, %rax                                     #11.12
        ret                                                     #11.12
...