Fonctionnement d'un ordinateur/Les registres du processeur
Un programmeur (ou un compilateur) qui souhaite programmer en langage machine peut manipuler les registres intégrés dans le processeur. À ce stade, il faut faire une petite remarque : tous les registres d'un processeur ne sont pas forcément manipulables par le programmeur. Il existe ainsi deux types de registres : les registres architecturaux, manipulables par des instructions, et les registres internes aux processeurs. Ces derniers servent à simplifier la conception du processeur ou mettre en œuvre des optimisations de performance. Dans ce qui suit, nous allons parler uniquement des registres architecturaux.
L'utilisation des registres[modifier | modifier le wikicode]
Les registres architecturaux se distinguent par le type de données que peuvent contenir leurs registres. Des processeurs ont des registres banalisés qui peuvent contenir tout type de données, tandis que d'autres ont des registres spécialisés pour chaque type de données. Les deux solutions ont des avantages et inconvénients différents. Elles sont toutefois complémentaires et non exclusives. Certains processeurs ont des registres généraux complémentés avec des registres spécialisés, pour des raisons de facilité.
Les registres spécialisés[modifier | modifier le wikicode]
Les registres spécialisés ont une utilité bien précise et leur fonction est fixée une bonne fois pour toutes. Un registre spécialisé est conçu pour stocker soit des nombres entiers, des flottants, des adresses, etc; mais pas autre chose. Pour ce qui est des registres spécialisés, le plus important est clairement le Program Counter. On peut aussi trouver les registres pour gérer la pile (le Stack Pointer et le Frame Pointer). Pour ce qui est des registres de données les plus courants, en voici la liste.
- Les registres entiers sont spécialement conçus pour stocker des nombres entiers.
- Les registres flottants sont spécialement conçus pour stocker des nombres flottants.
- Les registres de constante contiennent des constantes assez souvent utilisées. Par exemple, certains processeurs possèdent des registres initialisés à zéro pour accélérer la comparaison avec zéro ou l'initialisation d'une variable à zéro. On peut aussi citer certains registres flottants qui stockent des nombres comme \pi, ou e pour faciliter l'implémentation des calculs trigonométriques).
- Les registres d'Index servent à calculer des adresses, afin de manipuler rapidement des données complexes comme les tableaux.
Nous avons parlé de ces registres dans les chapitres précédents, ce qui fait que nous n'allons pas revenir dessus. Par contre, nous n’avons pas encore vu le registre spécialisé par excellence : le registre d'état.
Le registre d'état[modifier | modifier le wikicode]
Le registre d'état contient au minimum des bits qui indiquent le résultat d'une instruction de test. Il contient aussi d'autres bits, mais dont l'interprétation dépend du jeu d'instruction. Il arrive que le registre d'état soit mis à jour non seulement par les instructions de test, mais aussi par les instructions arithmétiques. Par exemple, si le résultat d'une opération arithmétique entraine un débordement d'entier, le registre d'état mémorisera ce débordement. Dans le chapitre précédent, nous avions vu que les débordements sont mémorisés par le processeur dans un bit dédié, appelé le bit de débordement. Et bien ce dernier est un bit du registre d'état. Il en est de même pour le bit de retenue vu dans le chapitre précédent, qui mémorise la retenue effectuée par une opération arithmétique comme une addition, une soustraction ou un décalage. En général, le registre d'état contient les bits suivants :
- le bit d'overflow, qui est mis à 1 lors d'un débordement d'entiers ;
- le bit de retenue, qui indique si une addition/soustraction a donné une retenue ;
- le bit null précise que le résultat d'une instruction est nul (vaut zéro) ;
- le bit de signe, qui permet de dire si le résultat d'une instruction est un nombre négatif ou positif.
Le bit de débordement est parfois présent en double : un bit pour les débordements pour les nombres non-signés, et un autre pour les nombres signés (en complément à deux). En effet, la manière de détecter les débordements n'est pas la même pour des nombres strictement positifs et pour des nombres en complément à deux. Certains processeurs s'en sortent avec un seul bit de débordement, en utilisant deux instructions d'addition : une pour les nombres signés, une autre pour les nombres non-signés. Mais d'autres processeurs utilisent une seule instruction d'addition pour les deux, qui met à jour deux bits de débordements : l'un qui détecte les débordements au cas où les deux opérandes sont signés, l'autre si les opérandes sont non-signées. Sur les processeurs ARM, c'est la seconde solution qui a été choisie. N'oublions pas les bits de débordement pour les entiers BCD, à savoir le bit de retenue et le bit half-carry, dont nous avions parlé au chapitre précédent.
- Le registre d'état n'est pas présent sur toutes les architectures, notamment sur les jeux d'instruction modernes, mais beaucoup d'architectures anciennes en ont un.
Sur certains processeurs, comme l'ARM1, chaque instruction arithmétique existe en deux versions : une qui met à jour le registre d'état, une autre qui ne le fait pas. L'utilité de cet arrangement n'est pas évident, mais il permet à certaines instructions arithmétiques de ne pas altérer le registre d'état, ce qui permet de conserver son contenu pendant un certain temps.
Le fait que le registre d'état est mis à jour par les instructions arithmétiques permet d'éviter de faire certains tests gratuitement. Par exemple, imaginons un morceau de code qui doit vérifier si deux entiers A et B sont égaux, avant de faire plusieurs opérations sur la différence entre les deux (A-B). Le code le plus basique pour cela fait la comparaison entre les deux entiers avec une instruction de test, effectue un branchement, puis fait la soustraction pour obtenir la différence, puis les calculs adéquats. Mais si la soustraction met à jour le registre d'état, on peut simplement faire la soustraction, faire un branchement qui teste le bit null du registre d'état, puis faire les calculs. Une petite économie toujours bonne à prendre.
Il faut noter que certaines instructions sont spécifiquement conçues pour altérer uniquement le registre d'état. Par exemple, sur les processeurs x86, certaines instructions ont pour but de mettre le bit de retenue à 0 ou à 1. Il existe en tout trois instructions capables de manipuler le bit de retenue : l'instruction CLC (CLear Carry) le met à 0, l'instruction STC (SeT Carry) le met à 1, l'instruction CMC (CompleMent Carry) l'inverse (passe de 0 à 1 ou de 1 à 0). Ces instructions sont utilisées de concert avec les instructions d'addition ADDC (ADD with Carry) et SUBC (SUB with Carry), qui effectuent le calcul A + B + Retenue et A - B - Retenue, et qui sont utilisées pour additionner/soustraire des opérandes plus grandes que les registres. Nous avions vu ces instructions dans le chapitre sur les instructions machines, aussi je ne reviens pas dessus.
Les registres généraux[modifier | modifier le wikicode]
Fournir des registres très spécialisés n'est pas très flexible. Prenons un exemple : j'ai un processeur disposant d'un Program Counter, de 4 registres entiers, de 4 registres d'Index pour calculer des adresses, et de 4 registres flottants. Si jamais j’exécute un morceau de programme qui manipule beaucoup de nombres entiers, mais qui ne manipule pas d'adresses ou de nombre flottants, j'utiliserais juste les 4 registres entiers. Une partie des registres du processeur sera inutilisé : tous les registres flottants et d'Index. Le problème vient juste du fait que ces registres ont une fonction bien fixée.
En réfléchissant, un registre est un registre, et il ne fait que stocker une suite de bits. Il peut tout stocker : adresses, flottants, entiers, etc. Pour plus de flexibilité, certains processeurs ne fournissent pas de registres spécialisés comme des registres entiers ou flottants, mais fournissent à la place des registres généraux utilisables pour tout et n'importe quoi. Ce sont des registres qui n'ont pas d'utilité particulière et qui peuvent stocker toute sorte d’information codée en binaire. Pour reprendre l'exemple du dessus, un processeur avec des registres généraux fournira un Program Counter et 12 registres généraux, qu'on peut utiliser sans vraiment de restrictions. On pourra s'en servir pour stocker 12 entiers, 10 entiers et 2 flottants, 7 adresses et 5 entiers, etc. Ce qui sera plus flexible et permettra de mieux utiliser les registres.
Les méthodes hybrides[modifier | modifier le wikicode]
Le choix entre registres spécialisés et registres généraux est une question de pragmatisme. Il existe bien des processeurs qui ne le sont pas et où tous les registres sont des registres généraux, même le Program Counter. Sur ces processeurs, on peut parfaitement lire ou écrire dans le Program Counter sans trop de problèmes. Ainsi, au lieu d'effectuer des branchements sur le Program Counter, on peut simplement utiliser une instruction qui ira écrire l'adresse à laquelle brancher dans le registre. On peut même faire des calculs sur le contenu du Program Counter : cela n'a pas toujours de sens, mais cela permet parfois d'implémenter facilement certains types de branchements avec des instructions arithmétiques usuelles.
D'autres processeurs font des choix moins extrême mais tout aussi discutables. Par exemple, l'ARM1 fusionne le registre d'état et le program counter en un seul registre de 32 bits... La raison à cela est que ce processeur manipule des manipule entiers et adresses de 32 bits, ce qui fait que ses registres font 32 bits, le le program counter ne fait pas exception. Mais le program counter n'a besoin que de 26 bits pour fonctionner. Il reste donc 32-26=6 bits à utiliser pour autre chose. De plus, les instructions de ce processeur font exactement 32 bits, pas un de plus ni de moins, et elles sont alignées en mémoire. Donc, les 2 bits de poids faibles du program counter sont inutilisés. Au total, cela fait 8 bits inutilisés. Et ils ont été réutilisés pour mémoriser les bits du registre d'état.
Mais le cas précédent est rare, très rare. Dans la réalité, les processeurs utilisent souvent une espèce de mélange entre les deux solutions. Généralement, une bonne partie des registres du processeur sont des registres généraux, à part quelques registres spécialisés, accessibles seulement à travers quelques instructions bien choisies. Sur les processeurs modernes, l'usage de registres spécialisés est tombé en désuétude, sauf évidemment pour le program counter. Les registres d'index ont disparus, les registres pour gérer la pile aussi, le registre d'état est en voie de disparition car il se marie mal avec les optimisations modernes que nous verrons dans quelques chapitres (pipeline, exécution dans le désordre, renommage de registres).
L'adressage des registres architecturaux[modifier | modifier le wikicode]
Outre leur taille, les registres du processeur se distinguent aussi par la manière dont on peut les adresser, les sélectionner. Les registres du processeur peuvent être adressés par trois méthodes différentes. À chaque méthode correspond un mode d'adressage différent. Les modes d'adressage des registres sont les modes d'adressages absolu (par adresse), inhérent (à nom de registre) et/ou implicite.
Les registres nommés[modifier | modifier le wikicode]
Dans le premier cas, chaque registre se voit attribuer une référence, une sorte d'identifiant qui permettra de le sélectionner parmi tous les autres. C'est un peu la même chose que pour la mémoire RAM : chaque byte de la mémoire RAM se voit attribuer une adresse bien précise. Pour les registres, c'est un peu la même chose : ils se voient attribuer quelque chose d'équivalent à une adresse, une sorte d'identifiant qui permettra de sélectionner un registre pour y accéder. Cet identifiant est ce qu'on appelle un nom de registre. Ce nom n'est rien d'autre qu'une suite de bits attribuée à chaque registre, chaque registre se voyant attribuer une suite de bits différente. Celle-ci sera intégrée à toutes les instructions devant manipuler ce registre, afin de sélectionner celui-ci. Ce numéro, ou nom de registre, permet d'identifier le registre que l'on veut, mais ne sort jamais du processeur : ce nom de registre, ce numéro, ne se retrouve jamais sur le bus d'adresse. Les registres ne sont donc pas identifiés par une adresse mémoire.

Les registres adressés[modifier | modifier le wikicode]
Mais il existe une autre solution, assez peu utilisée. Sur certains processeurs assez rares, on peut adresser les registres via une adresse mémoire. Il est vrai que c'est assez rare, et qu'à part quelques vielles architectures ou quelques microcontrôleurs, je n'ai pas d'exemples à donner. Mais c'est tout à fait possible ! C'est le cas du PDP-10.

Les registres adressés implicitement[modifier | modifier le wikicode]
Les registres de contrôle n'ont pas forcément besoin d'avoir un nom. Par exemple, la gestion de la pile se fait alors via des instructions Push et Pop qui sont les seules à pouvoir manipuler ces registres. Toute manipulation des registres de pile se faisant grâce à ces instructions, on n'a pas besoin de leur fournir un identifiant pour pouvoir les sélectionner. C'est aussi le cas du registre d'adresse d'instruction : sur certains processeurs, il est manipulé automatiquement par le processeur et par les instructions de branchement. C'est aussi le cas pour le Program Counter : à part sur certains processeurs vraiment très rares, on ne peut modifier son contenu qu'en utilisant des instructions de branchements. Idem pour le registre d'état, manipulé obligatoirement par les instructions de comparaisons et de test, et certaines opérations arithmétiques.
Dans ces cas bien précis, on n'a pas besoin de préciser le ou les registres à manipuler : le processeur sait déjà quels registres manipuler et comment, de façon implicite. Le seul moyen de manipuler ces registres est de passer par une instruction appropriée, qui fera ce qu'il faut. Les registres adressés implicitement sont presque toujours des registres de contrôle, beaucoup plus rarement des registres de données. Mais précisons encore une fois que sur certains processeurs, le registre d'état et/ou le Program Counter sont adressables, pareil pour les registres de pile. Inversement, il arrive que certains registres de données puissent être adressés implicitement, notamment certains registres impliqués dans la gestion des adresses mémoire.
La taille des registres architecturaux[modifier | modifier le wikicode]
Vous avez certainement déjà entendu parler de processeurs 32 ou 64 bits. Derrière cette appellation qu'on retrouve souvent dans la presse ou comme argument commercial se cache un concept simple. Il s'agit de la quantité de bits qui peuvent être stockés dans les registres principaux. Les registres principaux en question dépendent de l'architecture. Sur les architectures avec des registres généraux, la taille des registres est celle des registres généraux. Sur les autres architectures, la taille mentionnée est généralement celle des nombres entiers mais les autres registres peuvent avoir une taille totalement différente. Sur les processeurs x86, un registre pour les nombres entiers contient environ 64 bits tandis qu'un registre pour nombres flottants contient entre 80 et 256 bits (suivant les registres utilisés).
Le nombre de bits que peut contenir un registre est parfois différent de la largeur du bus de données (c'est à dire du nombre de bits qui peuvent transiter en même temps sur le bus de données). Exemple : sur les processeurs x86-32 bits, un registre stockant un entier fait 32bits alors que le bus de données peut contenir 64 bits en même temps. Cela a une petite incidence sur la façon dont une donnée est transférée entre la mémoire et un registre. On peut donc se retrouver dans deux situations différentes : soit le bus de données a une largeur égale à la taille d'un registre, soit la largeur du bus de données est plus petite que la taille d'un registre. Dans le premier cas, le bus de données peut charger en une seule fois le nombre de bits que peut contenir un registre. Dans le second cas, on ne peut pas charger le contenu d'un registre en une fois, et on doit charger ce contenu morceau par morceau.
La taille d'un registre est souvent une puissance de deux[modifier | modifier le wikicode]
Aujourd'hui, les processeurs utilisent presque tous des registres de la même taille que le byte, qui est une puissance de 2 (8, 16, 32, 64, 128, 256, voire 512 bits). Mais cette règle souffre évidemment d'exceptions. Aux tout débuts de l'informatique, certaines machines utilisaient des registres de 3, 7, 13, 17, 23, 36 et 48 bits ; mais elles sont aujourd'hui tombées en désuétude. On peut aussi citer les processeurs dédiés au traitement de signal audio, que l'on trouve dans les chaînes HIFI, les décodeurs TNT, les lecteurs DVD, etc. Ceux-ci utilisent des registres de 24 bits, car l'information audio est souvent codée par des nombres de 24 bits.
L'usage de bytes qui ne sont pas des puissances de 2 posent quelques problèmes techniques en termes d’adressage. Les problèmes en question surviennent sur les processeurs qui adressent la mémoire par mot (pour rappel, un mot est un groupe de plusieurs bytes). À partir de l'adresse d'un byte, le processeur doit en déduire l'adresse du mot à lire. Et une fois le mot récupéré, le processeur doit décider quel est le byte à prendre en compte. Un mot contenant N bytes, le calcul de l'adresse du mot est une simple division : on divise l'adresse du byte par N. Le reste de la division correspond à la position du byte dans le mot. Avec , la division est un simple décalage et le modulo est un simple ET logique, deux opérations très rapides. Si ce n'est pas le cas, on doit faire une vraie division et un vrai modulo, deux opérations excessivement lentes.
Le système d'aliasing de registres sur les processeurs x86[modifier | modifier le wikicode]
Sur les processeurs x86, on trouve des registres de taille différentes. Certains registres sont de 8 bits, d'autres de 16, d'autres de 32, et on a même des registres de 64 bits depuis plus d'une décennie. Limitons-nous pour le moment aux registres 8 et 16 bits, sur lesquels il y a beaucoup de choses à dire. Les premiers processeurs x86 étaient des processeurs 16 bits, mais ils s’inspiraient grandement des processeurs 8008 qui étaient des processeurs 8 bits. Le 8086 et le 8088 étaient en effet des versions améliorées et grandement remaniées des premiers 8008 d'Intel. En théorie, la rétrocompatibilité n'était pas garantie, dans le sens où les jeux d'instruction étaient différents entre le 8086 et le 8008. Mais Intel avait prévu quelques améliorations pour rendre la transition plus facile. Et l'une d'entre elle concerne directement le passage des registres de 8 à 16 bits.
Les registres 16 bits étaient découpés en deux portions de 8 bits, chacune adressable séparément. On pouvait adresser un registre de 16, ou alors adresser seulement les 8 bits de poids fort ou les 8 bits de poids faible. Ces octets étaient considérés comme des registres à part entière. Du moins, c'est le cas pour 4 registres de données, nommés AX, BX, CX et DX. le registre AX fait 16 bits, l'octet de poids fort est adressable comme un registre à part entière nommé AH, alors que l'octet de poids faible est aussi un registre nommé AL (H pour High et L pour Low). idem avec les registres BX, BH et BL, les registres CX, CH et CL, ou encore les registres DX, DH, DL. Pour ces registres, on a un système d'alias de registres, qui permet d'adresser certaines portions d'un registre comme un registre à part entière. Les registres AH, AL, BJH, BL, ..., ont tous un nom de registre et peuvent être utilisés dans des opérations arithmétiques ou logique ou autres. Dans ce cas, les opérations ne modifient que l'octet sélectionné, pas le reste du registre. Une même opération peut donc agir sur 16 ou 8 bits suivant le registre sélectionné. Les autres registres ne sont pas concernés, que ce soit les registres de données, d'adresse ou autres.
A départ, l'architecture x86 avait des registres de 16 bits. Puis, par la suite, l'architecture a étendu ses registres à 32 et enfin 64 bits. Mais cela s'est ressentit au niveau des registres, où le système d'alias a été étendu. Les registres 32 bits ont le même système d'alias, mais légèrement modifié. Sur un registre 32 bits, les 16 bits de poids faible sont adressables séparément, mais pas les 16 bits de poids fort. La raison est que les registres 16 bits originaux, présents sur les processeurs x86 16 bits, ont été étendus à 32 bits. Les 16 originaux sont toujours adressables comme avant, avec le même nom de registre que sur les anciens modèles. par contre, le registre étendu a un nouveau nom de registre. Pour rendre tout cela plus clair, voyons l'exemple du registre EAX des processeurs 64 bits. C'est un registre 32 bits, dont les 16 bits de poids fort sont tout simplement le registre AX vu plus haut, ce dernier pouvant être subdivisé en AH et AL. La même chose a lieu pour les registres EBX, ECX et EDX. Chose étonnante, presque tous les registres ont étés étendus ainsi, même le program counter, les registres liés à la pile et quelques autres.

Lors du passage au 64 bits, les registres 32 bits ont étés étendus de la même manière, et les registres étendus à 64 bits ont recus un nom de registre supplémentaires, RAX, RBX, RCX ou RDX. Le passage à 64 bits s'est accompagné de l'ajout de 4 nouveaux registres.
Un point intéressant est qu'Intel a beaucoup utilisé ce système d'alias pour éviter d'avoir à réellement ajouter certains registres. Dans le chapitre sur les architectures à parallélisme de données, nous verrons plusieurs cas assez impressionnants de cela. Pour le moment, bornons-nous à citer les exemples les plus frappants, sans rentrer dans les détails, et parlons du MMX, du SSE et de l'AVX.
Le MMX est une extension du x86, à savoir l'ajout d'instructions particulière au jeu d’instruction x86 de base. Cette extension ajoutait 8 registres appelés MM0, MM1, MM2, MM3, MM4, MM5, MM6 et MM7, d'une taille de 64 bits, qui ne pouvaient contenir que des nombres entiers. En théorie, on s'attendrait à ce que ces registres soient des registres séparés. Mais Intel utilisa le système d'alias pour éviter d'avoir à rajouter des registres. A la place, il étendit les registres flottants déjà existants, eux-même ajoutés par l'extension x87, qui définit 8 registres flottants de 80 bits. Chaque registre MMX correspondait aux 64 bits de poids faible d'un des 8 registres flottants de la x87 ! Cela posa pas mal de problèmes pour les programmeurs qui voulaient utiliser l'extension MMX. Il était impossible d'utiliser à la fois le MMX et les flottants X87...

Par la suite, Intel ajouta une nouvelle extension appelée le SSE, qui ajoutait plusieurs registres de 128 bits, les XMM registers illustrés ci-contre. Le SSE fût décliné en plusieurs versions, appelées SSE1, SSE2, SSE3, SS4 et ainsi de suite, chacune rajoutant de nouvelles instructions. Puis, Intel ajouta une nouvelle extension, l'AVX. L'AVX complète le SSE et ses extensions, en rajoutant quelques instructions, et surtout en permettant de traiter des données de 256 bits. Et cette dernière ajoute 16 registres d'une taille de 256 bits, nommés de YMM0 à YMM15 et dédiés aux instructions AVX. Et c'est là que le système dalias a encore frappé. Les registres AVX sont partagés avec les registres SSE : les 128 bits de poids faible des registres YMM ne sont autres que les registres XMM. Puis, arriva l'AVX-515 qui ajouta 32 registres de 512 bits, et des instructions capables de les manipuler, d'où son nom. Là encore, les 256 bits de poids faible de ces registres correspondent aux registres de l'AVX précédent. Du moins, pour les premiers 16 registres, vu qu'il n'y a que 16 registres de l'AVX normal.
Pour résumer, ce système permet d'éviter d'ajouter des registres de plus grande taille, en étendant des registres existants pour en augmenter la taille. Ce n'était peut-être pas sa fonction première, du moins sur les processeurs Intel, mais c’est ainsi qu'il a été utilisé à l'excès par Intel. En soi, la technique est intéressante et permet certainement des économies de circuits dignes de ce nom. La longévité des architectures x86 a fait que cette technique a beaucoup été utilisée, l'architecture ayant été étendue deux fois : lors du passage de 16 à 32 bits, puis de 32 à 64 bits. Le système d'extension a aussi été la source de plusieurs usage de l'aliasing de registres. Mais les autres architectures n'implémentent pas vraiment ce système. De plus, ce système marche assez mal avec les processeurs modernes, dont la conception interne se marie mal avec laliasing de registres, pour des raisons que nous verrons plus tard dans ce cours (cela rend plus difficile le renommage de registres et la détection des dépendances entre instructions).
Le pseudo-aliasing des registres sur le processeur Z80[modifier | modifier le wikicode]
Le processeur Z80 est très inspiré des premiers processeurs Intel, mais avec un jeu d'instruction légèrement différent. Il a lui aussi un système d'aliasing de registres, mais légèrement modifié. Le Z80 contient 8 paires de registres aliasés. On trouve ainsi deux paires de registres AF, deux paires BC, deux paires DE et deux paires HL. Chaque paire contient deux registres de 8 bits, mais une paire peut être considérée comme un registre unique de 16 bits, pour certaines opérations. Concrètement, le registre AF est un registre de 16 bits, composé de deux registres de 8 bits : le registre A et le registre F. Même chose pour le registre BC de 16 bits, composé du registre B de 8 bits et du registre C de 8 bits. Et ainsi de suite pour les paires DE et HL.
La quasi-totalité des opérations arithmétiques ne manipule que des registres de 8 bits. Il faut dire qu'à la base, le Z80 est un processeur de 8 bits. Mais le système de paires de registres permet d'effectuer une opération d'incrémentation sur une paire complète. Les paires sont concrètement utilisées seulement pour l'incrémentation, avec une instruction spécialisée. Cela peut paraitre étrange, mais c'est en réalité un petit plus qui se marie bien avec le reste de l'architecture. Le Z80 gère des adresses de 16 bits, ce qui signifie que son pointeur de pile et son program counter sont de 16 bits tous les deux. Aussi, pour mettre à jour le pointeur de pile et le program counter, le processeur incorpore un incrémenteur de 16 bits. Et ce même si il travaille sur des données de 8 bits et contient des circuits de calcul de 8 bits pour les données. les concepteurs du processeur ont sans doute cherché à rentabiliser cet incrémenteur et lui ont permit d'incrémenter des registres de données. Pour cela, il fallait regrouper les registres de 8 bits par paire de deux, ce qui rendait l’implémentation matérielle la plus simple possible. Formellement, ce n'est pas un système d'alias, mais un système où les registres sont regroupés lors de certaines opérations.
Les optimisations liées aux registres architecturaux[modifier | modifier le wikicode]
Afin d'améliorer les performances, les concepteurs des processeurs ont optimisé les registres architecturaux au mieux. Leur nombre, leur taille, leur adressage : tout est optimisé au maximum sur les jeux d'instruction dignes de ce nom. Mais sur certains processeurs, on trouve des optimisations assez spéciales, qui visent à dupliquer les registres architecturaux sans que cela se voit dans le jeu d'instruction. Pour le dire autrement, un registre architectural correspond à plusieurs registres physiques dans le processeur. Sur les processeurs récents, on utilise des techniques de renommage de registre, que l'on ne peut pas aborder pour le moment (par manque de concepts importants). Mais outre le renommage de registres, d'autres techniques similaires sur le principe sont possibles, comme le fenêtrage de registres.
Le fenêtrage de registres[modifier | modifier le wikicode]
Plus un processeur a de registres architecturaux, plus leur sauvegarde prend du temps. Pour limiter le temps de sauvegarde des registres, certains processeurs utilisent le fenêtrage de registres, une technique qui permet d'intégrer cette pile de registre directement dans les registres du processeur. Cette technique duplique chaque registre architectural en plusieurs exemplaires qui portent le même nom. Chaque ensemble de registre architecturaux forme une fenêtre de registre, qui contient autant de registres qu'il y a de registres architecturaux. Lorsqu'une fonction s’exécute, elle se réserve une fenêtre inutilisée, et peut utiliser les registres de la fenêtre comme bon lui semble : une fonction manipule le registre architectural de la fenêtre réservée, mais pas les registres avec le même nom dans les autres fenêtres. Ainsi, pas besoin de sauvegarder les registres de cette fenêtre, vu qu'ils étaient vides de toute donnée. S'il ne reste pas de fenêtre inutilisée, on est obligé de sauvegarder les registres d'une fenêtre dans la pile.
