Solo un experimento con respuestas dadas sobre "...que va a utilizar LEA
":
El siguiente código:
int main(int argc, char **argv)
{
#ifdef USE_SHIFTOR
return (argc << 1 | 1);
#else
return (2 * argc + 1);
#endif
}
voluntad, con gcc -fomit-frame-pointer -O8 -m{32|64}
(para 32 o 64 bits) compilar en el siguiente código de montaje:
- x86, de 32 bits:
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, de 64 bits:
00000000004004c0 <main>:
4004c0: 8d 44 3f 01 lea 0x1(%rdi,%rdi,1),%eax
4004c4: c3 retq
- x86 de 64 bits en
-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, de 32 bits,
-DUSE_SHIFTOR
: 00000000004004c0 <main>:
4004c0: 8d 04 3f lea (%rdi,%rdi,1),%eax
4004c3: 83 c8 01 or $0x1,%eax
4004c6: c3 retq
De hecho, es cierto que la mayoría de los casos usarán LEA
. Sin embargo, el código es no lo mismo para los dos casos. Hay dos razones para ello:
- Además puede desbordarse y se envuelven alrededor, mientras que las operaciones de bits como
<<
o |
no puede
(x + 1) == (x | 1)
sólo es cierto si !(x & 1)
demás la adición se traslada a la siguiente bit. En general, agregar uno solo hace que el bit más bajo se establezca en la mitad de los casos.
Si bien nosotros (y el compilador, probablemente) sepamos que el segundo es necesariamente aplicable, el primero sigue siendo una posibilidad. Por lo tanto, el compilador crea código diferente, ya que la "o la versión" requiere forzar bit cero a 1.
No lo sé con certeza, pero probablemente funcione según las mismas instrucciones de la máquina ... así que diría que escoja la que sea más legible. –
@Jon Seigel: Y "legible" significa lo que expresa más claramente la intención del código. ¿Está (el OP) multiplicándose por dos y agregando uno, o está cambiando a la izquierda y configurando el LSB? – jason
Está intentando hacer un trabajo que el compilador haría. Así que será mejor que no. ^^ – pinichi