Просто эксперимент, касающийся ответов, данных о "... он будет использовать LEA
":
Следующий код:
int main(int argc, char **argv)
{
#ifdef USE_SHIFTOR
return (argc << 1 | 1);
#else
return (2 * argc + 1);
#endif
}
, с gcc -fomit-frame-pointer -O8 -m{32|64}
(для 32 или 64 бит)) скомпилировать в следующий код сборки:
- x86, 32 бита:
080483a0 <main>:
80483a0: 8b 44 24 04 mov 0x4(%esp),%eax
80483a4: 8d 44 00 01 lea 0x1(%eax,%eax,1),%eax
80483a8: c3 ret
- x86, 64 бита:
00000000004004c0 <main>:
4004c0: 8d 44 3f 01 lea 0x1(%rdi,%rdi,1),%eax
4004c4: c3 retq
- x86, 64 бита,
-DUSE_SHIFTOR
: 080483a0 <main>:
80483a0: 8b 44 24 04 mov 0x4(%esp),%eax
80483a4: 01 c0 add %eax,%eax
80483a6: 83 c8 01 or $0x1,%eax
80483a9: c3 ret
- x86, 32 бита,
-DUSE_SHIFTOR
: 00000000004004c0 <main>:
4004c0: 8d 04 3f lea (%rdi,%rdi,1),%eax
4004c3: 83 c8 01 or $0x1,%eax
4004c6: c3 retq
Фактически, в большинстве случаев будет использоваться LEA
.Тем не менее, код не одинаков для двух случаев.Для этого есть две причины:
- сложение может переполниться и обернуться, в то время как битовые операции, такие как
<<
или |
, не могут (x + 1) == (x | 1)
, только если true !(x & 1)
иначе добавление переносится на следующий бит.Как правило, добавление единицы приводит к тому, что младший бит устанавливается в половине случаев.
Хотя мы (и, возможно, компилятор) знаем, что второе обязательно применимо, первое по-прежнемувозможность.Таким образом, компилятор создает другой код, поскольку для «or-version» необходимо установить нулевой бит в 1.