Considere este código simple:
void g();
void foo()
{
volatile bool x = false;
if (x)
g();
}
Puede ver que gcc
ni clang
optimizar la llamada potencial a g
. En mi opinión, esto es correcto: la máquina abstracta debe suponer que las volatile
variables pueden cambiar en cualquier momento (debido, por ejemplo, a un mapeo de hardware), por lo que el plegado constante de la false
inicialización en la if
comprobación sería incorrecto.
Pero MSVC elimina la llamada por g
completo ( volatile
¡aunque mantiene las lecturas y escrituras en el !). ¿Es este comportamiento compatible con el estándar?
Antecedentes: ocasionalmente uso este tipo de construcción para poder activar / desactivar la salida de depuración sobre la marcha: el compilador siempre debe leer el valor de la memoria, por lo que cambiar esa variable / memoria durante la depuración debería modificar el flujo de control en consecuencia . La salida de MSVC vuelve a leer el valor, pero lo ignora (presumiblemente debido a la eliminación constante del código y / o eliminación del código muerto), lo que, por supuesto, derrota mis intenciones aquí.
Ediciones:
volatile
Aquí se analiza la eliminación de las lecturas y escrituras : ¿está permitido que un compilador optimice una variable volátil local? (¡Gracias Nathan!). Creo que el estándar es muy claro que esas lecturas y escrituras deben suceder. Pero esa discusión no cubre si es legal que el compilador tome los resultados de esas lecturas por sentado y optimice en función de eso. Supongo que esto está sub / no especificado en el estándar, pero sería feliz si alguien demostrara que estoy equivocado.Por supuesto, puedo hacer
x
una variable no local para evitar el problema. Esta pregunta es más por curiosidad.
fuente
Respuestas:
Creo que [intro.execution] (el número de párrafo varía) podría usarse para explicar el comportamiento de MSVC:
El estándar no permite la eliminación de una lectura a través de un valor de gl volátil, pero el párrafo anterior podría interpretarse como que permite predecir el valor
false
.Por cierto, el estándar C (N1570 6.2.4 / 2) dice que
No está claro si podría haber un almacenamiento no explícito en un objeto con duración de almacenamiento automático en la memoria C / modelo de objeto.
fuente
volatile
compre (aparte de lecturas / escrituras superfluas) si se ignora para fines de optimización?TL; DR El compilador puede hacer lo que quiera en cada acceso volátil. Pero la documentación tiene que decirle: "La semántica de un acceso a través de un valor de volátil está definida por la implementación".
El estándar define para un programa secuencias permitidas de "accesos volátiles" y otros "comportamientos observables" (logrados mediante "efectos secundarios") que una implementación debe respetar según "la regla" como si ".
Pero el estándar dice (mi énfasis en negrita):
Del mismo modo para dispositivos interactivos (mi énfasis en negrita):
(De todos modos, el código específico que se genera para un programa no está especificado por el estándar).
Entonces, aunque el estándar dice que los accesos volátiles no se pueden eludir de las secuencias abstractas de los efectos secundarios abstractos de la máquina y los comportamientos observables consecuentes que algunos códigos (tal vez) definen, no puede esperar que nada se refleje en el código objeto o en el mundo real comportamiento a menos que la documentación del compilador le diga qué constituye un acceso volátil . Lo mismo para dispositivos interactivos.
Si está interesado en la volatilidad frente a las secuencias abstractas de los efectos secundarios abstractos de la máquina y / o los comportamientos observables consiguientes que algunos códigos (tal vez) definen , dígalo . Pero si está interesado en qué código objeto correspondiente se genera , debe interpretarlo en el contexto de su compilador y compilación .
Crónicamente, las personas creen erróneamente que para los accesos volátiles, una evaluación / lectura de máquina abstracta provoca una lectura implementada y una asignación / escritura de máquina abstracta provoca una escritura implementada. No hay ninguna base para esta creencia en ausencia de documentación de implementación que lo diga Cuando / si la implementación dice que en realidad hace algo en un "acceso volátil", la gente está justificada en esperar que algo, tal vez, la generación de cierto código objeto.
fuente
Creo que es legal omitir el cheque.
El párrafo que a todos les gusta citar
no implica que una implementación deba asumir que tales almacenes son posibles en cualquier momento o para cualquier variable volátil. Una implementación sabe qué tiendas son posibles. Por ejemplo, es completamente razonable suponer que tales escrituras implícitas solo ocurren para variables volátiles que se asignan a registros de dispositivos, y que dicha asignación solo es posible para variables con enlace externo. O una implementación puede suponer que tales escrituras solo se transfieren a ubicaciones de memoria alineadas con el tamaño de las palabras.
Dicho esto, creo que el comportamiento de MSVC es un error. No hay ninguna razón en el mundo real para optimizar la llamada. Tal optimización puede ser compatible, pero es innecesariamente malvada.
fuente
volatile
se supone que es una pista para la implementación de que el valor puede cambiar por medios desconocidos para la implementación.volatile
en esa plataforma y fuera de esa especificación, siempre será un juego de dados.volatile
hace y apegarse a eso. Mi punto es que el código en sí (de acuerdo con la máquina estándar / abstracta de C ++) no le permite determinar sig
se puede llamar.