GNT sans publicité, site mobile, fonctionnalitées exclusives...

Question sur les pointeurs restreints

Le
Taurre
Bonjour à tous,

Je me suis récemment penché sur la notion de pointeurs restreints
introduite par la Norme C99 et il y a plusieurs questions auxquelles
je n'ai trouvé aucune réponse:

- la première porte sur ce code:

#include <stdlib.h>


void
test (int *a, int *b, int * restrict v)
{
*a = *v;
*b = *v;
}


int
main (void)
{
int a;
int b;
int v = 10;

test (&a, &b, &v);
return EXIT_SUCCESS;
}

si j'ai bien saisit la notion de pointeur restreint cela signifie,
dans le cas de la fonction "test", que l'objet sur lequel pointe la
variable "v" ne peut-être accéder que via cette dernière. Donc, en
toute logique, on peut supposer que l'objet pointé par la variable "v"
ne sera pas modifié lors de l'exécution de cette fonction. Or, si je
compile ce code, j'obtiens ces lignes en assembleur pour la fonction
"test":

movl (%rdx), %eax
movl %eax, (%rdi)
movl (%rdx), %eax
movl %eax, (%rsi)

la valeur de l'objet pointé par la variable "v" est chargé deux fois
dans le registre eax alors qu'elle ne devrait l'être qu'une seule
fois l'optimisation n'aura lieu que si un ou les deux autres
pointeurs sont également déclaré avec le qualificatif "restrict".
Quelqu'un pourrait-il m'expliquer pourquoi?

- la deuxième porte sur le même code, mais avec des variables de type
char. Dans cette hypothèse, même si les trois pointeurs sont déclar=
és
avec le qualificatif "restrict", aucune optimisation n'est effectuée
et j'obtiens donc:

movzbl (%rdx), %eax
movb %al, (%rdi)
movzbl (%rdx), %eax
movb %al, (%rsi)

Je précise que je compile avec GCC et l'option d'optimisation -O2
Merci d'avance pour vos réponses.
Lire les 32 réponses

Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 7
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Marc
Le #23305951
Taurre wrote:

void
test (int *a, int *b, int * restrict v)
{
*a = *v;
*b = *v;
}


[...]
si j'ai bien saisit la notion de pointeur restreint cela signifie,
dans le cas de la fonction "test", que l'objet sur lequel pointe la
variable "v" ne peut-être accéder que via cette dernière. Donc, en
toute logique, on peut supposer que l'objet pointé par la variable "v"
ne sera pas modifié lors de l'exécution de cette fonction. Or, si je
compile ce code, j'obtiens ces lignes en assembleur pour la fonction
"test":

movl (%rdx), %eax
movl %eax, (%rdi)
movl (%rdx), %eax
movl %eax, (%rsi)

la valeur de l'objet pointé par la variable "v" est chargé deux fois
dans le registre eax alors qu'elle ne devrait l'être qu'une seule
fois... l'optimisation n'aura lieu que si un ou les deux autres
pointeurs sont également déclaré avec le qualificatif "restrict".
Quelqu'un pourrait-il m'expliquer pourquoi?



En fait ce sont "a" et "v" dont tu veux indiquer l'indépendance au
compilateur.

char c[42];
test(c,b,c+1);
--> l'écriture dans *a modifie la valeur *v.
(sur une archi où les int sont forcément alignés, ça ne serait pas
absurde de faire l'optimisation sans restrict j'ai l'impression, mais
je peux rater quelque chose)

- la deuxième porte sur le même code, mais avec des variables de type
char. Dans cette hypothèse, même si les trois pointeurs sont déclarés
avec le qualificatif "restrict", aucune optimisation n'est effectuée



Essaie un gcc plus récent alors.
Taurre
Le #23306231
On 24 avr, 00:06, Marc
Taurre  wrote:
> void
> test (int *a, int *b, int * restrict v)
> {
>         *a = *v;
>         *b = *v;
> }
[...]
> si j'ai bien saisit la notion de pointeur restreint cela signifie,
> dans le cas de la fonction "test", que l'objet sur lequel pointe la
> variable "v" ne peut-être accéder que via cette dernière. Donc, e n
> toute logique, on peut supposer que l'objet pointé par la variable "v "
> ne sera pas modifié lors de l'exécution de cette fonction. Or, si j e
> compile ce code, j'obtiens ces lignes en assembleur pour la fonction
> "test":

> movl       (%rdx), %eax
> movl       %eax, (%rdi)
> movl       (%rdx), %eax
> movl       %eax, (%rsi)

> la valeur de l'objet pointé par la variable "v" est chargé deux foi s
> dans le registre eax alors qu'elle ne devrait l'être qu'une seule
> fois... l'optimisation n'aura lieu que si un ou les deux autres
> pointeurs sont également déclaré avec le qualificatif "restrict".
> Quelqu'un pourrait-il m'expliquer pourquoi?

En fait ce sont "a" et "v" dont tu veux indiquer l'indépendance au
compilateur.

char c[42];
test(c,b,c+1);
--> l'écriture dans *a modifie la valeur *v.
(sur une archi où les int sont forcément alignés, ça ne serait pa s
absurde de faire l'optimisation sans restrict j'ai l'impression, mais
je peux rater quelque chose)

> - la deuxième porte sur le même code, mais avec des variables de ty pe
> char. Dans cette hypothèse, même si les trois pointeurs sont décl arés
> avec le qualificatif "restrict", aucune optimisation n'est effectuée

Essaie un gcc plus récent alors.



Tout d'abord, merci pour cette réponse :)

En fait ce sont "a" et "v" dont tu veux indiquer l'indépendance au
compilateur.

char c[42];
test(c,b,c+1);
--> l'écriture dans *a modifie la valeur *v.



Oui, mais n'est ce pas un comportement interdit? Normalement, en
qualifiant le pointeur "v" de restreint, on indique au compilateur que
l'objet sur lequel il pointe ne sera accéder que via lui-même ou un
pointeur dérivé de lui. Or, dans cet exemple ce n'est pas le cas, les
pointeurs "a" et "v" accèdent au même objet (enfin pas tout à fait,
mais une partie de l'objet pointé par "v" est accéder via "a" ce qui
constitue un comportement indéterminé il me semble).

Essaie un gcc plus récent alors.



C'est vrai que je suis sous Debian Squeeze et que ma version n'est pas
la plus récente (4-4), je vais essayer avec une autre, merci du
conseil ;)
Marc
Le #23306701
Taurre wrote:

En fait ce sont "a" et "v" dont tu veux indiquer l'indépendance au
compilateur.

char c[42];
test(c,b,c+1);
--> l'écriture dans *a modifie la valeur *v.



Oui, mais n'est ce pas un comportement interdit? Normalement, en
qualifiant le pointeur "v" de restreint, on indique au compilateur que
l'objet sur lequel il pointe ne sera accéder que via lui-même ou un
pointeur dérivé de lui. Or, dans cet exemple ce n'est pas le cas, les
pointeurs "a" et "v" accèdent au même objet (enfin pas tout à fait,
mais une partie de l'objet pointé par "v" est accéder via "a" ce qui
constitue un comportement indéterminé il me semble).



C'est aussi comme ça que j'avais compris restrict au début, mais
ensuite j'ai regardé ce que faisait gcc, et les exemples donnés par le
standard, et ça ne collait pas bien.

exemple 1:
int * restrict a;
int * restrict b;
extern int c[];

exemple 2:
void f(int n, int * restrict p, int * restrict q)
{
while (n-- > 0)
*p++ = *q++;
}

autre exemple:
void *memcpy(void *restrict s1, const void *restrict s2, size_t n);

À chaque fois (sauf pour la variable extern) restrict est mis en
double. Le texte n'a pas changé dans C1X, c'est toujours aussi peu
clair.

Il est possible aussi que gcc soit trop conservateur.

Essaie un gcc plus récent alors.



C'est vrai que je suis sous Debian Squeeze et que ma version n'est pas
la plus récente (4-4), je vais essayer avec une autre, merci du
conseil ;)



Je vais tuer le suspens, mais j'avais essayé avant de poster, et ça
fait la même optimisation que pour int.
Taurre
Le #23307011
On 24 avr, 14:31, Marc
Taurre  wrote:
>> En fait ce sont "a" et "v" dont tu veux indiquer l'indépendance au
>> compilateur.

>> char c[42];
>> test(c,b,c+1);
>> --> l'écriture dans *a modifie la valeur *v.

> Oui, mais n'est ce pas un comportement interdit? Normalement, en
> qualifiant le pointeur "v" de restreint, on indique au compilateur que
> l'objet sur lequel il pointe ne sera accéder que via lui-même ou un
> pointeur dérivé de lui. Or, dans cet exemple ce n'est pas le cas, l es
> pointeurs "a" et "v" accèdent au même objet (enfin pas tout à fai t,
> mais une partie de l'objet pointé par "v" est accéder via "a" ce qu i
> constitue un comportement indéterminé il me semble).

C'est aussi comme ça que j'avais compris restrict au début, mais
ensuite j'ai regardé ce que faisait gcc, et les exemples donnés par l e
standard, et ça ne collait pas bien.

exemple 1:
int * restrict a;
int * restrict b;
extern int c[];

exemple 2:
void f(int n, int * restrict p, int * restrict q)
{
      while (n-- > 0)
            *p++ = *q++;

}

autre exemple:
void *memcpy(void *restrict s1, const void *restrict s2, size_t n);

À chaque fois (sauf pour la variable extern) restrict est mis en
double. Le texte n'a pas changé dans C1X, c'est toujours aussi peu
clair.

Il est possible aussi que gcc soit trop conservateur.

>> Essaie un gcc plus récent alors.

> C'est vrai que je suis sous Debian Squeeze et que ma version n'est pas
> la plus récente (4-4), je vais essayer avec une autre, merci du
> conseil ;)

Je vais tuer le suspens, mais j'avais essayé avant de poster, et ça
fait la même optimisation que pour int.



Voilà qui répond parfaitement à mes interrogations!
Merci beaucoup :)
Antoine Leca
Le #23310151
Taurre écrivit :
si j'ai bien saisit la notion de pointeur restreint cela signifie,
dans le cas de la fonction "test", que l'objet sur lequel pointe la
variable "v" ne peut-être accéder que via cette dernière.



Dans ton exemple, v est à la fois une variable int de valeur 10, et un
pointeur restreint (vers la première.) Je ne suis pas sûr que cela
facilite la compréhension pour nous autres humains.


Donc, en toute logique, on peut supposer que l'objet pointé par la
variable "v" ne sera pas modifié lors de l'exécution de cette fonction.



Oui, puisque le code ne modifie pas le pointeur, et le propos de
restrict est d'affirmer que d'autres modifications n'ont pas lieu par
ailleurs.


la valeur de l'objet pointé par la variable "v" est chargé deux fois
dans le registre eax alors qu'elle ne devrait l'être qu'une seule
fois...



« devrait » : pas d'accord. La norme est limpide, restrict est une
opportunité d'optimisation, pas une obligation imposée au compilateur.


l'optimisation n'aura lieu que si un ou les deux autres
pointeurs sont également déclaré avec le qualificatif "restrict".
Quelqu'un pourrait-il m'expliquer pourquoi?



Il faudrait demander aux développeurs de GCC.


- la deuxième porte sur le même code, mais avec des variables de type
char. Dans cette hypothèse, même si les trois pointeurs sont déclarés
avec le qualificatif "restrict", aucune optimisation n'est effectuée



Là encore, c'est un sujet pour GCC. À mon sens, tu peux avoir le cas
théorique où les pointeurs pointent vers le même mot mémoire (un mot
pouvant être constitué de plusieurs bytes), et GCC veux peut-être éviter
les problèmes liés à des accès concurrents à un même mot.
Cela étant, ce peut être aussi un bête bogue dans le code de GCC...
Dans tous les cas, c'est totalement conforme à la norme, en vertu de ce
qui est rappelé ci-dessus: restrict n'est pas une obligation.


Antoine
Publicité
Suivre les réponses
Poster une réponse
Anonyme