Je me suis toujours demandé pourquoi les processeurs s'arrêtaient à 32 registres. C'est de loin la pièce la plus rapide de la machine, pourquoi ne pas simplement faire de plus gros processeurs avec plus de registres? Cela ne signifierait-il pas moins d'aller à la RAM?
computer-architecture
Matt Capone
la source
la source
Réponses:
Premièrement, toutes les architectures de processeur ne se sont pas arrêtées sur 32 registres. Presque toutes les architectures RISC qui ont 32 registres exposés dans le jeu d'instructions ont en réalité 32 registres d'entiers et 32 registres de plus en virgule flottante (donc 64). (Le virgule flottante "add" utilise des registres différents du nombre entier "add".) L’architecture SPARC a des fenêtres de registre.. Sur SPARC, vous ne pouvez accéder qu'à 32 registres d'entiers à la fois, mais les registres agissent comme une pile et vous pouvez pousser et faire apparaître de nouveaux registres 16 à la fois. L'architecture Itanium de HP / Intel comportait 128 registres d'entiers et 128 registres à virgule flottante exposés dans le jeu d'instructions. Les GPU modernes de NVidia, AMD, Intel, ARM et Imagination Technologies exposent tous un grand nombre de registres dans leurs fichiers. (Je sais que cela est vrai des architectures NVidia et Intel, je ne connais pas très bien les jeux d'instructions AMD, ARM et Imagination, mais je pense que les fichiers de registre sont volumineux également.)
Deuxièmement, la plupart des microprocesseurs modernes implémentent le changement de nom de registre de pour éliminer la sérialisation inutile causée par la nécessité de réutiliser les ressources. Ainsi, les fichiers de registre physique sous-jacents peuvent être plus volumineux (96, 128 ou 192 registres sur certaines machines). Ceci élimine une partie des fichiers. nécessité pour le compilateur de générer autant de noms de registre uniques, tout en fournissant un fichier de registre plus volumineux au planificateur.
Il peut être difficile d’augmenter encore le nombre de registres exposés dans le jeu d’instructions pour deux raisons. Tout d'abord, vous devez pouvoir spécifier les identificateurs de registre dans chaque instruction. 32 registres nécessitent un spécificateur de registre sur 5 bits. Par conséquent, les instructions à 3 adresses (communes sur les architectures RISC) utilisent 15 bits sur 32 bits pour spécifier les registres. Si vous augmentiez cela à 6 ou 7 bits, vous disposeriez de moins d'espace pour spécifier des codes opération et des constantes. Les GPU et Itanium ont des instructions beaucoup plus volumineuses. Les instructions plus volumineuses ont un coût: vous devez utiliser plus de mémoire d'instructions, votre comportement en cache d'instructions est donc moins idéal.
La deuxième raison est le temps d'accès. Plus vous créez une mémoire importante, plus il est lent pour accéder aux données de celle-ci. (Juste en termes de physique de base: les données sont stockées dans un espace à 2 dimensions, donc si vous stockez bits, la distance moyenne par rapport à un bit spécifique est O ( √n .) Un fichier de registre est juste une petite mémoire multiport, et l’une des contraintes pour l’agrandir est qu’il soit nécessaire de commencer à synchroniser votre machine plus lentement pour pouvoir stocker le fichier de registre plus volumineux. Habituellement, en termes de performance totale, c'est une perte. O(n−−√)
la source
Encore deux raisons de limiter le nombre de registres:
la source
Un grand nombre de codes comporte de nombreux accès à la mémoire (30% est un chiffre typique). En dehors de cela, environ les 2/3 sont des accès en lecture et les 1/3 sont des accès en écriture. Cela n’est pas dû au manque de registres, mais aussi à l’accès aux tableaux, aux variables de membre d’objet, etc.
Cela doit être fait en mémoire (ou en cache de données) en raison de la fabrication du C / C ++ (tout ce que vous pouvez obtenir d’un pointeur doit avoir une adresse qui doit être potentiellement stockée en mémoire). Si le compilateur peut deviner que vous n'écrirez pas les variables à l'aide de superbes astuces de pointeur indirect, il les mettra dans des registres, ce qui convient parfaitement aux variables de fonction, mais pas aux variables globalement accessibles (généralement, tout ce qui sort de malloc). ()), car il est essentiellement impossible de deviner comment l’état global changera.
Pour cette raison, il n'est pas courant que le compilateur puisse faire quoi que ce soit avec plus de 16 registres d'utilisation générale de toute façon. C'est pourquoi tous les architectes populaires en ont à peu près autant (ARM en a 16).
Les MIPS et les autres RISC ont tendance à en avoir 32 car il n’est pas très difficile d’avoir autant de registres: le coût est suffisamment bas, c’est un peu un "pourquoi pas?". Plus de 32 sont pour la plupart inutiles et présentent l'inconvénient d'allonger l'accès au fichier de registre (chaque doublement du nombre de registres ajoute potentiellement une couche supplémentaire de multiplexeurs, ce qui ajoute un peu plus de retard ...). Cela rend également les instructions légèrement plus longues en moyenne - ce qui signifie que lorsque vous exécutez le type de programme qui dépend de la largeur de bande de la mémoire d'instructions, vos registres supplémentaires vous ralentissent!
Si votre unité centrale de traitement est en ordre et ne renomme pas les registres et que vous essayez d'effectuer beaucoup d'opérations par cycle (plus de 3), alors en théorie, vous avez besoin de davantage de registres à mesure que votre nombre d'opérations par cycle augmente. C'est pourquoi l'Itanium a tant de registres! Mais en pratique, mis à part le code orienté numériquement à virgule flottante ou orienté SIMD (pour lequel Itanium était vraiment bon), la plupart des codes auront beaucoup de lectures / écritures en mémoire et de sauts rendant impossible ce rêve de plus de trois opérations par cycle. (en particulier dans les logiciels orientés serveur comme les bases de données, les compilateurs, les exécutions de langages de haut niveau comme le javascript, les émulations, etc.). C'est ce qui a coulé l'Itanium.
Tout se résume à la différence entre le calcul et l'exécution!
la source
Qui vous dit que le processeur a toujours 32 registres? x86 a 8, ARM 32 bits et x86_64 en ont 16, IA-64 en a 128 et bien d’autres. Vous pouvez jeter un oeil ici . Même les architectures MIPS, PPC ou toutes les architectures qui ont 32 registres à usage général dans le jeu d'instructions, le nombre est beaucoup plus grand que 32 puisqu'il y a toujours des registres d'indicateurs (le cas échéant), des registres de contrôle ... sans compter les registres renommés et les registres de matériel.
Tout a son prix. Plus le nombre de registres est important, plus vous avez du travail lors du changement de tâche, plus vous avez besoin d'espace pour coder les instructions. Si vous avez moins de registres, vous n'avez pas besoin de stocker et de restaurer beaucoup lorsque vous appelez et revenez de fonctions ou que vous changez de tâche sans avoir à remplacer l'absence de registres dans un code de calcul étendu.
En outre, plus le fichier de registre est volumineux, plus il sera coûteux et complexe. La mémoire SRAM étant la RAM la plus rapide et la plus chère, elle n’est utilisée que dans le cache du processeur. Mais cela reste beaucoup moins cher et prend moins de surface qu'un fichier de registre avec la même capacité.
la source
Par exemple, un processeur Intel typique possède "officiellement" 16 registres entiers et 16 registres vectoriels. Mais en réalité, il y en a beaucoup plus: Le processeur utilise le "renommage de registre". Si vous avez une instruction reg3 = reg1 + reg2, vous rencontreriez un problème si une autre instruction utilisant reg3 n'avait pas encore fini. Vous ne pouvez pas exécuter la nouvelle instruction si elle écrase reg3 avant qu'elle ait été lue par l'instruction précédente.
Il y a donc environ 160 registres réels . Ainsi, l'instruction simple ci-dessus est remplacée par "regX = reg1 + reg2 et rappelez-vous que regX contient reg3". Sans registres de renom, une exécution déréglée serait absolument morte.
la source
Je ne suis pas un ingénieur électricien, mais je pense qu'une autre possibilité pour limiter le nombre de registres est le routage. Il y a un nombre limité d'unités arithmétiques et elles doivent être capables de prendre une entrée de chaque registre et une sortie vers chaque registre. Cela est particulièrement vrai lorsque vous avez des programmes en pipeline capables d'exécuter de nombreuses instructions par cycle.
J'ai eu l'idée de cette réponse en regardant quelques-uns des discours d'Ivan Godard sur le processeur de Mill. Une partie de l’innovation de la CPU Mill est que vous ne pouvez pas sortir sur des registres arbitraires - les sorties sont toutes placées dans une pile de registres ou "ceinture", ce qui réduit donc les problèmes de routage, car vous savez toujours où la sortie sera dirigée. Notez qu'ils ont toujours le problème de routage pour obtenir les registres d'entrée vers les unités arithmétiques.
Voir L'architecture CPU de Mill - The Belt (2 sur 9) pour l'énoncé du problème et la solution de Mill.
la source
Quant à la MIPS ISA, Hennessy et Patterson, 4ème édition de l' organisation et de la conception informatique p. 176, répond directement à cette question spécifique:
la source