web-dev-qa-db-fra.com

La différence entre la mémoire asm, asm volatile et clobbering

Lors de la mise en œuvre de structures de données sans verrouillage et de code de synchronisation, il est souvent nécessaire de supprimer les optimisations du compilateur. Normalement, les gens le font en utilisant asm volatile avec memory dans la liste de clobber, mais vous voyez parfois juste asm volatile ou simplement une mémoire asm clobbering simple.

Quel impact ces différentes déclarations ont-elles sur la génération de code (en particulier dans GCC, car il est peu probable qu'il soit portable)?

Juste pour référence, ce sont les variations intéressantes:

asm ("");   // presumably this has no effect on code generation
asm volatile ("");
asm ("" ::: "memory");
asm volatile ("" ::: "memory");
59
jleahy

Voir la page "Extended Asm" dans la documentation GCC .

Vous pouvez empêcher la suppression d'une instruction asm en écrivant le mot clé volatile après le asm. [...] Le mot clé volatile indique que l'instruction a des effets secondaires importants. GCC ne supprimera pas un asm volatile s'il est accessible.

et

Une instruction asm sans aucun opérande de sortie sera traitée de manière identique à une instruction asm volatile.

Aucun de vos exemples n'a de opérande de sortie spécifié, donc les asm et asm volatile les formulaires se comportent de manière identique: ils créent un point dans le code qui ne peut pas être supprimé (sauf s'il est prouvé qu'il est inaccessible).

Ce n'est pas tout à fait la même chose que de ne rien faire. Voir cette question pour un exemple de mannequin asm qui change la génération de code - dans cet exemple, le code qui fait le tour d'une boucle 1000 fois est vectorisé en code qui calcule 16 itérations de la boucle immediatement; mais la présence d'un asm à l'intérieur de la boucle inhibe l'optimisation (le asm doit être atteint 1000 fois).

Le "memory" clobber fait supposer à GCC que toute mémoire peut être lue ou écrite arbitrairement par le bloc asm, donc empêchera le compilateur de réorganiser les charges ou les magasins à travers lui:

Cela empêchera GCC de conserver les valeurs de la mémoire en cache dans les registres de l'instruction d'assembleur et n'optimisera pas les stockages ou les charges dans cette mémoire.

(Cela n'empêche pas un processeur de réorganiser les charges et les magasins par rapport à un autre processeur, cependant, vous avez besoin d'instructions de barrière de mémoire réelles pour cela.)

54
Matthew Slattery

asm ("") ne fait rien (ou du moins, il n'est pas censé faire quoi que ce soit.

asm volatile ("") ne fait rien non plus.

asm ("" ::: "memory") est une simple barrière de compilation.

asm volatile ("" ::: "memory") AFAIK est le même que le précédent. Le mot clé volatile indique au compilateur qu'il n'est pas autorisé à déplacer ce bloc Assembly. Par exemple, il peut être hissé hors d'une boucle si le compilateur décide que les valeurs d'entrée sont les mêmes à chaque appel. Je ne sais pas vraiment dans quelles conditions le compilateur décidera qu'il comprend suffisamment l'assembly pour essayer d'optimiser son placement, mais le mot clé volatile le supprime complètement. Cela dit, je serais très surpris si le compilateur tentait de déplacer une instruction asm qui n'avait aucune entrée ou sortie déclarée.

Par ailleurs, volatile empêche également le compilateur de supprimer l'expression s'il décide que les valeurs de sortie ne sont pas utilisées. Cela ne peut se produire que s'il existe des valeurs de sortie, donc cela ne s'applique pas à asm ("" ::: "memory").

6
Lily Ballard

Juste pour être complet sur réponse de Lily Ballard , Visual Studio 2010 propose _ReadBarrier(), _WriteBarrier() et _ReadWriteBarrier() pour faire de même (VS2010 ne fait pas ' t autoriser l'assemblage en ligne pour les applications 64 bits).

Celles-ci ne génèrent aucune instruction mais affectent le comportement du compilateur. Un bel exemple est ici .

MemoryBarrier() génère lock or DWORD PTR [rsp], 0

3
James