Considere este código simples:
void g();
void foo()
{
volatile bool x = false;
if (x)
g();
}
Você pode ver que gcc
nem clang
otimiza a chamada potencial para g
. Isso está correto no meu entendimento: A máquina abstrata deve assumir que as volatile
variáveis podem mudar a qualquer momento (devido a serem, por exemplo, mapeadas por hardware), portanto, dobrar constantemente a false
inicialização na if
verificação estaria errado.
Mas o MSVC elimina g
totalmente a chamada (mantendo as leituras e gravações no volatile
entanto!). Esse comportamento é compatível com os padrões?
Antecedentes: Ocasionalmente uso esse tipo de construção para ativar / desativar a saída de depuração on-the-fly: O compilador sempre deve ler o valor da memória, portanto, alterar a variável / memória durante a depuração deve modificar o fluxo de controle adequadamente . A saída MSVC relê o valor, mas o ignora (provavelmente devido à constante dobragem e / ou eliminação do código morto), o que obviamente derrota minhas intenções aqui.
Editar% s:
A eliminação das leituras e gravações
volatile
é discutida aqui: É permitido que um compilador otimize uma variável volátil local? (obrigado Nathan!). Eu acho que o padrão é bastante claro de que essas leituras e gravações devem acontecer. Mas essa discussão não cobre se é legal para o compilador considerar os resultados dessas leituras como garantidos e otimizar com base nisso. Suponho que isso seja sub / não especificado no padrão, mas ficaria feliz se alguém me provasse errado.É claro que posso criar
x
uma variável não local para contornar o problema. Esta questão é mais por curiosidade.
fonte
Respostas:
Eu acho que [intro.execution] (número do parágrafo varia) poderia ser usado para explicar o comportamento da MSVC:
O padrão não permite a eliminação de uma leitura através de um valor de volume volátil, mas o parágrafo acima pode ser interpretado como permitindo prever o valor
false
.BTW, o Padrão C (N1570 6.2.4 / 2) afirma que
Não está claro se poderia haver um armazenamento não explícito em um objeto com duração de armazenamento automático na memória C / modelo de objeto.
fonte
volatile
lhe compre (exceto leituras / gravações supérfluas) se for ignorada para fins de otimização?TL; DR O compilador pode fazer o que quiser em cada acesso volátil. Mas a documentação deve lhe informar .-- "A semântica de um acesso através de um valor volátil volátil é definida pela implementação".
O padrão define para um programa sequências permitidas de "acessos voláteis" e outros "comportamentos observáveis" (alcançados através de "efeitos colaterais") que uma implementação deve respeitar de acordo com "a regra 'como se'".
Mas o padrão diz (minha ênfase em negrito):
Da mesma forma para dispositivos interativos (ênfase em negrito):
(De qualquer forma, qual código específico é gerado para um programa não é especificado pelo padrão.)
Portanto, embora o padrão diga que acessos voláteis não podem ser eliminados das seqüências abstratas dos efeitos colaterais da máquina abstrata e consequentes comportamentos observáveis que algum código (talvez) define, você não pode esperar que nada seja refletido no código de objeto ou no mundo real comportamento, a menos que a documentação do compilador informe o que constitui um acesso volátil . O mesmo vale para dispositivos interativos.
Se você está interessado em volatilidade em relação às seqüências abstratas dos efeitos colaterais da máquina abstrata e / ou comportamentos observáveis consequentes que algum código (talvez) define, então o diga . Mas se você estiver interessado em qual código de objeto correspondente é gerado , deve interpretá-lo no contexto de seu compilador e compilação .
Cronicamente, as pessoas acreditam erroneamente que, para acessos voláteis, uma avaliação / leitura abstrata da máquina causa uma leitura implementada e uma atribuição / gravação abstrata da máquina causa uma gravação implementada. Não há base para essa crença na documentação de implementação ausente dizendo isso. Quando / se a implementação diz que realmente faz algo com um "acesso volátil", as pessoas são justificadas em esperar que algo - talvez, a geração de determinado código de objeto.
fonte
Eu acredito que é legal pular o cheque.
O parágrafo que todo mundo gosta de citar
não implica que uma implementação deva assumir que tais armazenamentos são possíveis a qualquer momento ou para qualquer variável volátil. Uma implementação sabe quais lojas são possíveis. Por exemplo, é inteiramente razoável supor que tais gravações implícitas só acontecem para variáveis voláteis mapeadas para registros de dispositivos e que esse mapeamento só é possível para variáveis com ligação externa. Ou uma implementação pode assumir que tais gravações só ocorrem em locais de memória alinhados e com tamanho de palavra.
Dito isto, acho que o comportamento do MSVC é um bug. Não há motivo do mundo real para otimizar a chamada. Essa otimização pode ser compatível, mas é desnecessariamente má.
fonte
volatile
é suposto ser uma dica para a implementação que o valor pode mudar por meios desconhecidos para a implementação.volatile
nessa plataforma e fora dessa especificação, sempre será uma porcaria.volatile
faz e manter isso. O que quero dizer é que o próprio código (de acordo com a máquina padrão / abstrata C ++) não permite que você determine seg
pode ser chamado.