Restrict
Dans le langage de programmation C, à partir du standard C99, restrict
est un mot-clé qui peut être utilisé dans les déclarations de pointeur. Le mot-clé restrict
est une déclaration d'intention donnée par le programmeur pour le compilateur. Il indique que pour la durée de vie du pointeur, seul le pointeur lui-même ou une valeur directement issue (comme pointer + 1
) sera utilisé pour accéder à l'objet vers lequel il pointe. Cela limite les effets de l'aliasing de pointeur, aidant aux optimisations. Si la déclaration d'intention n'est pas respectée et que l'objet est atteint par un pointeur indépendant, cela se traduira par un comportement indéfini. L'utilisation du mot-clé restrict
permet, en principe, d'obtenir la même performance que le même programme écrit en Fortran[1].
C++ n'a pas de support standard de restrict
, mais de nombreux compilateurs ont des équivalents qui fonctionnent habituellement en C++ et en C, tels que __restrict__ pour GCC et Clang , et __restrict et __declspec(restrict) pour Visual C++.
Optimisation
Si le compilateur sait qu'il y a seulement un pointeur vers un bloc de mémoire, il peut produire un code mieux optimisé. Nous allons le voir sur un exemple.
Version sans restrict
Considérons la fonction en C suivante :
void updatePtrs(size_t *ptrA, size_t *ptrB, size_t *val) { *ptrA += *val; *ptrB += *val; }
La fonction updatePtrs
ci-dessus prend 3 pointeurs ptrA
, ptrB
, et val
vers des entiers non signés (size_t
) en paramètres. La fonctionne incrémente les valeurs pointés par ptrA
, ptrB
de l'entier pointé par val
. Les pointeurs ptrA
, ptrB
, et val
peuvent se référer au même emplacement mémoire. C'est pourquoi le compilateur pourrait générer un code moins optimal :
load R1 ← *val ; Charge la valeur pointé par val load R2 ← *ptrA ; Charge la valeur pointé par ptrA add R2 += R1 ; Effectuer une Addition set R2 → *ptrA ; mettre à jour la valeur pointé par ptrA ; De même pour ptrB, notez que val est chargé à deux reprises, parce que ; ptrA peut être égal à val (c'est à dire, pointe vers le même emplacement). load R1 ← *val load R2 ← *ptrB add R2 += R1 set R2 → *ptrB
Version avec restrict
Toutefois, si le mot-clé restrict
est utilisé et que la fonction ci-dessus est déclarée comme :
void updatePtrs(size_t *restrict ptrA, size_t *restrict ptrB, size_t *restrict val);
alors le compilateur suppose que ptrA
, ptrB
et val
pointent vers différents emplacements. Ainsi, la mise à jour d'un pointeur n'affectera pas les autres pointeurs. En particulier, on sait que la valeur pointé par val
n'est pas modifiée. Il suffit donc de lire la valeur *val
une fois seule pour réaliser les deux additions *ptrA += *val;
et *ptrB += *val;
. Le compilateur peut générer un meilleur code comme suit :
load R1 ← *val load R2 ← *ptrA add R2 += R1 set R2 → *ptrA ; Notez que val n'est pas rechargé, ; parce que le compilateur sait que c'est inchangé load R2 ← *ptrB add R2 += R1 set R2 → *ptrB
Notez que le code assembleur est plus court parce que la valeur pointée par val
n'est chargée qu'une seule fois.
On peut remarquer que dans notre cas, ces deux signatures génère aussi le même code :
void updatePtrs(size_t *ptrA, size_t *ptrB, size_t *restrict val); void updatePtrs(size_t *restrict ptrA, size_t *ptrB, size_t *val);
En effet, il est suffisant de promettre au compilateur que ptrA
n'écrira pas dans val
, ou que val
ne sera pas modifié par ptrA
. Ce n'est pas vrai pour ptrB
à cause de l'ordre des opérations dans la fonction.
C'est le programmeur (non le compilateur) qui est responsable de veiller à ce que les pointeurs ne pointent pas les mêmes endroits.
Références
- (en) Cet article est partiellement ou en totalité issu de l’article de Wikipédia en anglais intitulé « restrict » (voir la liste des auteurs).
- (en) « ISO/IEC 9899:TC2 Committee Draft », sur ISO, (consulté le ), p. 108–112
- ↑ Ulrich Drepper, « Memory part 5: What programmers can do », What every programmer should know about memory, sur What every programmer should know about memory, lwn.net, : « "...The default aliasing rules of the C and C++ languages do not help the compiler making these decisions (unless restrict is used, all pointer accesses are potential sources of aliasing). This is why Fortran is still a preferred language for numeric programming: it makes writing fast code easier. (In theory the restrict keyword introduced into the C language in the 1999 revision should solve the problem. Compilers have not caught up yet, though. The reason is mainly that too much incorrect code exists which would mislead the compiler and cause it to generate incorrect object code.)" »
Voir aussi
Articles connexes
- Const
Liens externes
- Demystifying The Restrict Keyword : explanation and examples of use
- Douglas Walls, « How to Use the restrict Qualifier in C », sur Oracle (consulté le )
- Restricted Pointers in C : the original rationale behind the definition
Portail de la programmation informatique