web-dev-qa-db-fra.com

Le compilateur est-il autorisé à plier constamment un volatile local?

Considérez ce code simple:

void g();

void foo()
{
    volatile bool x = false;
    if (x)
        g();
}

https://godbolt.org/z/I2kBY7

Vous pouvez voir que ni gcc ni clang n'optimisent l'appel potentiel à g. Ceci est correct dans ma compréhension: la machine abstraite est de supposer que les variables volatile peuvent changer à tout moment (en raison de leur mappage matériel par exemple), donc en repliant constamment l'initialisation false dans le if la vérification serait erronée.

Mais MSVC élimine complètement l'appel à g (en conservant les lectures et écritures dans le volatile!). Ce comportement est-il conforme aux normes?


Contexte: J'utilise parfois ce type de construction pour pouvoir activer/désactiver la sortie de débogage à la volée: le compilateur doit toujours lire la valeur de la mémoire, donc changer cette variable/mémoire pendant le débogage devrait modifier le flux de contrôle en conséquence . La sortie MSVC relit la valeur mais l'ignore (probablement en raison du pliage constant et/ou de l'élimination du code mort), ce qui, bien sûr, annule mes intentions ici.


Modifications:

  • L'élimination des lectures et écritures dans volatile est discutée ici: Est-il permis à un compilateur d'optimiser une variable volatile locale? (merci Nathan!). Je pense que la norme est très claire: ces lectures et écritures doivent se produire. Mais cette discussion ne couvre pas s'il est légal pour le compilateur de prendre les résultats de ces lectures pour acquis et d'optimiser en fonction de cela. Je suppose que c'est sous-/non spécifié dans la norme, mais je serais heureux si quelqu'un me prouvait le contraire.

  • Je peux bien sûr faire de x une variable non locale pour contourner le problème. Cette question est plus par curiosité.

25
Max Langhof

Je pense que [intro.execution] (le numéro de paragraphe varie) pourrait être utilisé pour expliquer le comportement de MSVC:

Une instance de chaque objet avec une durée de stockage automatique est associée à chaque entrée dans son bloc. Un tel objet existe et conserve sa dernière valeur stockée pendant l'exécution du bloc et pendant la suspension du bloc ...

La norme ne permet pas d'éliminer une lecture à travers une valeur gl volatile, mais le paragraphe ci-dessus pourrait être interprété comme permettant de prédire la valeur false.


BTW, la norme C (N1570 6.2.4/2) dit que

Un objet existe, a une adresse constante et conserve sa dernière valeur stockée pendant toute sa durée de vie.34


34) Dans le cas d'un objet volatil, la dernière mémoire n'a pas besoin d'être explicite dans le programme.

Il n'est pas clair s'il pourrait y avoir un stockage non explicite dans un objet avec une durée de stockage automatique dans le modèle de mémoire/objet C.

2
Language Lawyer

TL; DR Le compilateur peut faire ce qu'il veut sur chaque accès volatile. Mais la documentation doit vous le dire .-- "La sémantique d'un accès via une valeur gl volatile est définie par l'implémentation."


La norme définit pour un programme des séquences autorisées d '"accès volatils" et d'autres "comportements observables" (obtenus via des "effets secondaires") qu'une implémentation doit respecter selon "la règle" comme si ".

Mais la norme dit (mon accent gras):

Projet de travail, norme pour le langage de programmation C++
Numéro de document: N4659
Date: 21/03/2017

§ 10.1.7.1 Les cv-qualifiers

5 La sémantique d'un accès via une valeur gl volatile est définie par l'implémentation. […]

De même pour les appareils interactifs (mon accent gras):

§ 4.6 Exécution du programme

5 Une implémentation conforme exécutant un programme bien formé doit produire le même comportement observable que l'une des exécutions possibles de l'instance correspondante de la machine abstraite avec le même programme et la même entrée. [...]

7 Les exigences minimales pour une implémentation conforme sont:

(7.1) - Les accès via des valeurs de glissement volatiles sont évalués strictement selon les règles de la machine abstraite.
(7.2) - À la fin du programme, toutes les données écrites dans des fichiers doivent être identiques à l'un des résultats possibles que l'exécution du programme selon la sémantique abstraite aurait produit.
(7.3) - La dynamique d'entrée et de sortie des dispositifs interactifs doit se dérouler de telle manière qu'une invite de sortie soit réellement délivrée avant qu'un programme n'attende l'entrée. Ce qui constitue un appareil interactif est défini par l'implémentation.

Ceux-ci sont collectivement appelés le comportement observable du programme. [...]

(Quoi qu'il en soit quel code spécifique est généré pour un programme n'est pas spécifié par la norme.)

Donc, bien que la norme dise que les accès volatils ne peuvent pas être éliminés des séquences abstraites d'effets secondaires de la machine abstraite et des comportements observables conséquents que certains codes (peut-être) définissent, vous ne pouvez pas vous attendre à ce que quoi que ce soit soit reflété dans le code objet ou le monde réel sauf si la documentation de votre compilateur vous indique ce qui constitue un accès volatile . Idem pour les appareils interactifs.

Si vous êtes intéressé par la volatilité vis à vis des séquences abstraites d'effets secondaires de la machine abstraite et/ou des comportements observables conséquents que certains codes (peut-être) définissent alors - dites-le. Mais si vous êtes intéressé par quel code objet correspondant est généré , vous devez interpréter cela dans le contexte de votre compilateur & compilation .

Chroniquement les gens croient à tort que pour les accès volatils, une évaluation/lecture de machine abstraite provoque une lecture implémentée et une affectation/écriture de machine abstraite provoque une écriture implémentée. Il n'y a aucune base pour cette croyance en l'absence de documentation d'implémentation le disant. Quand/iff l'implémentation dit qu'elle fait fait quelque chose sur un "accès volatile", les gens sont en droit d'attendre que quelque chose - peut-être, la génération de certains code objet.

2
philipxy