Es cierta que al menos un compilador de C++ reconocerá la situación (cuando el 0 es conocido en tiempo de compilación) y convertirlo en un no-op:
Fuente
inline int shift(int what, int bitcount)
{
return what >> bitcount ;
}
int f() {
return shift(42,0);
}
interruptores compilador
icpc -S -O3 -mssse3 -fp-model fast=2 bitsh.C
Intel C++ 11.0 ensamblaje
# -- Begin _Z1fv
# mark_begin;
.align 16,0x90
.globl _Z1fv
_Z1fv:
..B1.1: # Preds ..B1.0
movl $42, %eax #7.10
ret #7.10
.align 16,0x90
# LOE
# mark_end;
.type _Z1fv,@function
.size _Z1fv,.-_Z1fv
.data
# -- End _Z1fv
.data
.section .note.GNU-stack, ""
# End
Como se puede ver en ..B1.1, Intel recopila "desplazamiento de retorno (42,0)" a "volver 42."
Intel 11 también entresaca el cambio de estas dos variaciones:
int g() {
int a = 5;
int b = 5;
return shift(42,a-b);
}
int h(int k) {
return shift(42,k*0);
}
Para el caso en que el valor de desplazamiento no se puede conocer en tiempo de compilación ...
int egad(int m, int n) {
return shift(42,m-n);
}
... el cambio no puede se debe evitar ...
# -- Begin _Z4egadii
# mark_begin;
.align 16,0x90
.globl _Z4egadii
_Z4egadii:
# parameter 1: 4 + %esp
# parameter 2: 8 + %esp
..B1.1: # Preds ..B1.0
movl 4(%esp), %ecx #20.5
subl 8(%esp), %ecx #21.21
movl $42, %eax #21.10
shrl %cl, %eax #21.10
ret #21.10
.align 16,0x90
# LOE
# mark_end;
... pero al menos está en línea, por lo que no hay sobrecarga de llamadas.
Montaje extra: volátil es caro. La fuente ...
int g() {
int a = 5;
volatile int b = 5;
return shift(42,a-b);
}
... en lugar de un no-op, compila a ...
..B3.1: # Preds ..B3.0
pushl %esi #10.9
movl $5, (%esp) #12.18
movl (%esp), %ecx #13.21
negl %ecx #13.21
addl $5, %ecx #13.21
movl $42, %eax #13.10
shrl %cl, %eax #13.10
popl %ecx #13.10
ret #13.10
.align 16,0x90
# LOE
# mark_end;
... así que si usted está trabajando en una máquina donde los valores se presiona en la pila puede que no sea lo mismo cuando los muestres, bueno, esta optimización perdida es probablemente la menor de tus molestias.
Eso sería específico del compilador, no creo que el estándar * requiera * que se cree la llamada a la función. La optimización global podría fácilmente descartar la llamada a la función si se pasaba bitCount como una constante 0 y posiblemente incluso como una variable que contiene cero (aunque habría código para examinar la variable al menos, por lo que no sería un no-op) . Depende completamente del compilador. – paxdiablo
Por supuesto, una vez dicho esto, nunca he visto un compilador en la naturaleza que tenga ese nivel de optimización. Sospecho que el retorno de la inversión no sería suficiente para garantizarlo. – paxdiablo
Pax, VC9 hace "fuera de la caja" (configuración de versión predeterminada) para: ---- int Ajuste (int x, int shift) { if (shift> 0) {/ * bloque grande que impide la alineación * /} return x << shift; } ---- Incluso cuando se realiza una llamada desde una unidad de traducción diferente, al pasar shift = 0, la llamada y >> se eliminarán. ¡Muy impresionante! – peterchen