Que peuvent faire les êtres humains du qualificatif de ressortingction?

Si le mot clé de ressortingct C99 est correct, qualifier un pointeur sur ce point est une promesse faite que les données qu’il référence ne seront pas modifiées derrière le pseudo du compilateur.

En revanche, si je comprends le qualificatif const est considéré comme une documentation imposée par le compilateur selon laquelle un object donné ne sera pas modifié derrière le dos d’un humain écrivant du code. Le compilateur peut avoir un indice comme effet secondaire, mais en tant que programmeur, je ne m’en soucie pas vraiment.

De la même manière, conviendrait-il de considérer un qualificatif de ressortingct dans un prototype de fonction comme une exigence obligeant l’utilisateur à garantir un access exclusif (“éviter le repliement du spectre” ou peut-être quelque chose de plus fort) pendant la durée de l’appel? Devrait-il être utilisé comme “documentation”?

De plus, y a-t-il quelque chose à comprendre dans le fait que ressortingct qualifie un pointeur plutôt que les données qu’il pointe (comme le fait const )?

EDIT: À l’origine, j’imaginais que ressortingct pouvait avoir des implications avec le code threadé, mais cela semble faux, j’élimine les références aux threads de la question pour éviter toute confusion.

La meilleure «intuition» à propos du mot clé ressortingct est que c’est une garantie (du programmeur au compilateur) que, pendant la durée de vie du pointeur, la mémoire accessible via ce pointeur ne sera accessible qu’avec ce pointeur et non via un autre pointeur. ou référence ou adresse globale. Il est donc important que le pointeur soit la propriété du pointeur et de la mémoire, en liant les deux jusqu’à ce que le pointeur disparaisse.

Chris Dodd a la description correcte du mot clé. Sur certaines plates-formes, cela peut être très important pour des raisons de performances, car il permet au compilateur de savoir qu’une fois qu’il a chargé des données via ce pointeur dans un registre, il n’est pas nécessaire de le refaire. Sans cette garantie, le compilateur doit recharger les données via un pointeur à chaque fois qu’un autre pointeur éventuellement pseudonyme est écrit, ce qui peut provoquer un blocage sérieux du pipeline appelé magasin de stockage en magasin .

const et ressortingct sont des concepts différents, et ce n’est pas le cas que const implique ressortingct . Tout ce que const dit, c’est que vous n’écrirez pas via ce pointeur dans le cadre de cette fonction . Un pointeur const peut toujours être aliasé. Par exemple, considérons:

 int foo( const int *a, int * b ) { *b *= 2; return *a + *b; // induces LHS: *a must be read back immediately // after write has cleared the store queue } 

Bien que vous ne puissiez pas écrire directement dans a fonction de cette fonction, il serait parfaitement légal d’appeler foo comme:

 int x = 3; foo( &x, &x ); // returns 12 

ressortingct est une garantie différente: une promesse que a != b dans tous les appels à foo() .

J’ai longuement parlé du mot-clé ressortingct et de ses conséquences sur les performances , tout comme Mike Acton . Bien que nous parlions d’un PowerPC en ordre spécifique, le problème load-hit-store existe également sur le x86, mais son exécution dans le désordre rend ce blocage plus difficile à isoler dans un profil.

Et juste pour souligner: ceci n’est pas une optimisation obscure ou prématurée, si vous vous souciez de la performance. ressortingct peut conduire à des accélérations très importantes s’il est utilisé correctement.

La plupart de ce que vous savez est faux!

const ne garantit pas que quelque chose ne changera pas derrière le dos du compilateur. Tout ce que cela fait, c’est vous empêcher d’écrire à cet endroit. Cependant, quelque chose d’autre pourrait encore être capable d’écrire à cet emplacement. Le compilateur ne peut donc PAS supposer qu’il est constant.

Comme d’autres l’ont dit, le qualificatif de ressortingction concerne le crénelage. En fait, lors du premier cycle de normalisation C, il y avait une proposition pour un mot clé “noalias”. Malheureusement, la proposition était assez mal rédigée – elle fut à l’origine de la seule et unique fois où Dennis Ritchie s’est impliqué au cours de ce processus, lorsqu’il a écrit une lettre dans laquelle il était dit que “Noalias doit disparaître. Cela ne peut pas être négocié. ”

Il va sans dire que «noalias» ne faisait pas partie du C. Lorsque le moment est venu de réessayer, la proposition a été écrite suffisamment mieux pour que ressortingct soit incluse dans la norme – et même si noalias aurait probablement été un nom plus significatif. pour lui, ce nom était tellement corrompu que je doute que quiconque ait même envisagé d’essayer de l’utiliser.

Dans tous les cas, l’intention principale de ressortingct est d’indiquer au compilateur qu’il n’y aura pas d’alias de cet élément. Une des raisons est que les objects puissent être stockés temporairement dans des registres. Par exemple, considérons quelque chose comme:

 void f(int *a, int *b, int *c) { for (int i=0; i<*a; i++) *b += c[i]; } 

Le compilateur veut vraiment mettre i dans un registre et charger * a dans un registre. Ainsi, lorsque vient le temps de décider d'exécuter une autre itération de la boucle, il ne fait que comparer les valeurs de ces registres. Malheureusement, cela ne peut pas être fait - si quelqu'un qui utilisait cette fonction était complètement fou et l'appelait avec a == b, chaque fois qu'il écrit à * b dans la boucle, cette nouvelle valeur est aussi la valeur de * a - il doit donc lire * de mémoire à chaque itération de la boucle, au cas où celui qui l'appellerait était complètement fou. Utiliser ressortingct indique au compilateur qu'il peut générer du code en supposant que a et b seront toujours distincts, donc écrire dans * a ne changera jamais * b (ou l'inverse).

Votre compréhension est en grande partie correcte. Le qualificatif de ressortingct indique simplement que les données auxquelles un pointeur qualifié est accessible ne sont accessibles que par ce pointeur exact. Cela s’applique aussi bien aux écritures qu’aux écritures.

Le compilateur ne se soucie pas des threads concurrents, il ne va pas générer le code différemment, et vous pouvez brouiller vos propres données à votre guise. Mais il faut savoir quelles opérations de pointeur peuvent changer quelle mémoire globale.

Ressortingct contient également un avertissement API aux humains indiquant qu’une fonction donnée est implémentée avec l’hypothèse de parameters sans alias.

Aucun locking par l’utilisateur n’est nécessaire pour le compilateur. Il veut seulement s’assurer qu’il lit correctement les données qui étaient censées être compressées, par code que le compilateur était censé générer , au cas où il n’y aurait pas de qualificatif de ressortingct . L’ajout de ressortingct libère de cette préoccupation.

Enfin, notez que le compilateur parsingra probablement déjà les alias possibles en fonction des types de données, aux niveaux d’optimisation les plus élevés. Par conséquent, ressortingct est important pour les fonctions comportant plusieurs pointeurs vers le même type de données. Vous pouvez tirer une leçon de ce sujet et vous assurer que tous les pseudonymes délibérés que vous faites sont faits via un union .

Nous pouvons voir ressortingct en action:

 void move(int *a, int *b) { void move(int *__ressortingct a, int *__ressortingct b) { a[0] = b[0]; a[0] = b[0]; a[1] = b[0]; a[1] = b[0]; } } movl (%edx), %eax movl (%edx), %edx movl %eax, (%ecx) movl %edx, (%eax) movl (%edx), %eax movl %edx, 4(%eax) movl %eax, 4(%ecx) 

Dans la colonne de droite, avec ressortingct , le compilateur n’a pas besoin de relire b[0] partir de la mémoire. Il était capable de lire b[0] et de le conserver dans le registre %edx , puis de simplement stocker le registre deux fois dans la mémoire. Dans la colonne de gauche, il ne savait pas si le magasin à a peut-être changé b .

Quelqu’un de plus familier avec la norme pourrait probablement donner une meilleure réponse, mais je vais tenter le coup.

“Les données ne seront pas modifiées derrière le compilateur” sonne plus comme l’opposé de “volatile” pour moi.

“const” signifie que les données ne seront pas modifiées devant le programmeur; c’est-à-dire qu’elle ne peut pas modifier les données via le signifiant marqué “const” (j’écris “signifiant” car dans int const *pi , le nom pi n’est pas const, mais *pi est). Les données peuvent être modifiables via un autre signifiant (les données non const peuvent être transmises à une fonction en tant que données const).

Ce “restreindre” qualifie les pointeurs est la clé. Les pointeurs sont le seul moyen d’aliaser les données en C, ils sont donc le seul moyen d’accéder à certaines données via deux noms différents. “restreindre” consiste à limiter l’access aux données à un seul chemin d’access.

Cela peut être un exemple tiré d’un domaine extrêmement étroit, mais la plate-forme Nios II d’Altera est un microcontrôleur logiciel que vous pouvez personnaliser au sein d’un FPGA. Ensuite, dans le code source C de ce micro, vous pouvez utiliser un outil C-to-Hardware pour accélérer les boucles internes à l’aide d’un matériel personnalisé, plutôt que par logiciel.

Dans celui-ci, l’utilisation du mot clé __ressortingct__ (identique à celui de C99) permet à l’outil C2H d’optimiser correctement l’accélération matérielle du fonctionnement du pointeur en parallèle plutôt que séquentiellement. Au moins dans ce cas, la ressortingct n’est tout simplement pas destinée à la consommation humaine. Voir aussi la page de Sun sur ressortingct , où la première ligne indique

L’utilisation appropriée du qualificatif de ressortingct dans les programmes C peut permettre au compilateur de produire des exécutables beaucoup plus rapides.

Si quelqu’un souhaite en savoir plus sur C2H, ce PDF traite de l’optimisation des résultats de C2H. La section sur __ressortingct__ trouve à la page 20.