Considere la siguiente función:
void func(bool& flag)
{
if(!flag) flag=true;
}
Me parece que si la bandera tiene un valor booleano válido, esto sería equivalente a configurarlo incondicionalmente true
, así:
void func(bool& flag)
{
flag=true;
}
Sin embargo, ni gcc ni clang lo optimizan de esta manera; ambos generan lo siguiente en el -O3
nivel de optimización:
_Z4funcRb:
.LFB0:
.cfi_startproc
cmp BYTE PTR [rdi], 0
jne .L1
mov BYTE PTR [rdi], 1
.L1:
rep ret
Mi pregunta es: ¿es solo que el código es un caso demasiado especial para preocuparse por optimizarlo, o hay buenas razones por las que dicha optimización no sería deseada, dado que flag
no es una referencia a volatile
? Parece que la única razón que podría ser es que de flag
alguna manera podría tener un valor no true
-o- false
sin un comportamiento indefinido en el momento de leerlo, pero no estoy seguro de si esto es posible.
c++
optimization
Ruslan
fuente
fuente
1
uso. godbolt.org/g/swe0tcRespuestas:
Esto puede afectar negativamente al rendimiento del programa debido a consideraciones de coherencia de la caché . Escribir en
flag
cada vez quefunc()
se llama ensuciaría la línea de caché que lo contiene. Esto sucederá independientemente del hecho de que el valor que se escribe coincide exactamente con los bits encontrados en la dirección de destino antes de la escritura.EDITAR
hvd ha proporcionado otra buena razón que impide tal optimización. Es un argumento más convincente en contra de la optimización propuesta, ya que puede resultar en un comportamiento indefinido, mientras que mi respuesta (original) solo abordó aspectos de rendimiento.
Después de reflexionar un poco más, puedo proponer un ejemplo más de por qué los compiladores deberían estar estrictamente prohibidos, a menos que puedan demostrar que la transformación es segura para un contexto particular, de introducir la escritura incondicional. Considere este código:
Con una escritura incondicional,
func()
esto definitivamente desencadena un comportamiento indefinido (escribir en la memoria de solo lectura terminará el programa, incluso si el efecto de la escritura sería, de lo contrario, no operativo).fuente
const
para pasar a una función que puede modificar los datos que es la fuente del comportamiento indefinido, no la escritura incondicional. Doctor, duele cuando hago esto ....Aparte de la respuesta de Leon sobre el rendimiento:
Suponer
flag
estrue
. Suponga que dos hilos están llamando constantementefunc(flag)
. La función tal como está escrita, en ese caso, no almacena nadaflag
, por lo que debería ser seguro para subprocesos. Dos hilos acceden a la misma memoria, pero solo para leerla. Establecer incondicionalmenteflag
atrue
significa que dos subprocesos diferentes escribirían en la misma memoria. Esto no es seguro, no es seguro incluso si los datos que se escriben son idénticos a los datos que ya están allí.fuente
[intro.races]/21
.0x01
en un byte que ya0x01
causa un comportamiento "inseguro". En un sistema con acceso a memoria word o dword lo haría; pero el optimizador debe ser consciente de esto. En una PC moderna o un sistema operativo de teléfono, no ocurre ningún problema. Entonces esta no es una razón válida.flag
está en una página de copia sobre escritura. Ahora, a nivel de CPU, el comportamiento podría estar definido (error de página, deje que el sistema operativo lo maneje), pero a nivel de sistema operativo, todavía puede estar indefinido, ¿verdad?No estoy seguro sobre el comportamiento de C ++ aquí, pero en C la memoria podría cambiar porque si la memoria contiene un valor distinto de cero que no sea 1, permanecería sin cambios con la verificación, pero cambiaría a 1 con la verificación.
Pero como no soy muy fluido en C ++, no sé si esta situación es posible.
fuente
_Bool
?bool
/_Bool
y significatrue
, entonces en ese ABI en particular, probablemente tenga razón._Bool
y C ++bool
son del mismo tipo o tipos compatibles que siguen las mismas reglas. Con MSVC, tienen el mismo tamaño y alineación, pero no hay una declaración oficial sobre si usan las mismas reglas.<stdbool.h>
incluye untypedef _Bool bool;
Y sí, en x86 (al menos en la V ABI System),bool
/_Bool
están obligados a ser 0 o 1, con los bits superiores del byte borran. No creo que esta explicación sea plausible.func
se pasó en RDI, mientras que Windows usaría RDX).