Étudier le cours Compilateurs, je suis laissé à merveille pourquoi utiliser des registres du tout.
Il est souvent le cas que l'appelant ou la callee doit D'une manière, ils finissent toujours par utiliser la pile de toute façon. Crée une complexité supplémentaire en utilisant des registres en vaut vraiment la peine? P>
Excusez mon ignorance. P>
mise à jour: s'il vous plaît, je sais que les registres sont plus rapides que la RAM et d'autres types de cache. Ma principale préoccupation est que l'on doit "enregistrer" la valeur qui se trouve dans le registre et la "restauration" au registre après. Dans les deux cas, nous accédons à une sorte de cache. Ne serait-il pas préférable d'utiliser le cache en premier lieu? P>
7 Réponses :
Cela peut faire une énorme différence. Une fois, j'ai dirigé le compilateur sur PowerPC / Macintosh pour mettre les bonnes variables locales dans des registres et obtenu une accélération de 2 fois la tâche principale de l'application. La tâche était essentiellement liée à la CPU, mais élimine les accès à la mémoire à l'aide de registres donnant la vitesse 2 fois. L'accélération peut être beaucoup plus dramatique dans d'autres circonstances. P>
C'était dans une fonction de feuille. Il n'a pas appelé d'autres fonctions. P>
Deux fois plus vite ne sont rien. Vous obtenez cela pour passer de Java à C ++. Les différences réelles sont des ordres de grossitude (si vous ne parlez pas d'utilisation de registres du tout).
Dans la hiérarchie de la vitesse / de la latence, les registres sont les plus rapides (généralement la latence de cycle zéro), le cache L1 est ensuite (typiquement 1 cycles de latence), puis il descend rapidement après cela. Donc, dans General Register Accesses sont «Gratuits», alors qu'il y a toujours des coûts impliqués dans les accès à la mémoire, même lorsque cet accès est mis en cache. P>
Sauver et restaurer des registres ne se produit généralement qu'à la fin d'un appel de fonction ou d'un interrupteur de contexte, ou (b) lorsque le compilateur s'élève à des registres pour des variables temporaires et doit "renvoyer" un ou plusieurs registres retour à la mémoire. En général, le code bien optimisé conserve la majorité des variables fréquemment consultées ("chaudes") dans des registres, au moins dans la ou les boucles latérales d'une fonction. P>
Oui je comprends ça. Mais nous devons souvent «sauver» et «restaurer» les valeurs dans et vers des registres. C'est ma préoccupation principale. Question mise à jour.
Voir le paragraphe ajouté dans une réponse ci-dessus.
Mais pourquoi les CPus ne pouvaient-ils pas simplement utiliser le fichier de registre comme un "cache de niveau 0 CPU", spécifiquement ciblé pour fonctionner avec la pile?
Accéder à la RAM est généralement beaucoup plus lent que l'accès à un registre à la fois en termes de latence et de bande passante. Il existe des CPU qui ont une pile quincaillerie de taille limitée - cela permet de pousser les registres à la pile et de les éclater - mais ils utilisent toujours des registres directement pour des calculs. Travailler avec une machine pure pile (dont de nombreux exemples académiques) est plutôt difficile aussi, en ajoutant plus de complexité. P>
La différence entre les machines à base de piles et de registres est floue. Beaucoup de machines de registre modernes utilisent un registre de renommage pour masquer la pile, que seules les données de déversement à la pile réelle lorsqu'ils manquent de registres internes. Certaines machines de piles anciennes ont fait quelque chose de similaire, de pipelining plusieurs instructions et de peephole optimisant une séquence POW-Modify-POP dans une modification en place. P>
La manière dont les processeurs modernes utilisent l'exécution de la parallèle fantaisie des instructions, il ne s'agit probablement pas de différentes différences entre les machines de pile contre registre. Les machines d'inscription peuvent avoir un léger bord car le compilateur peut donner de meilleures notes sur la réutilisation des données, mais une machine de pile LISP d'un milliard de dollars se ferait rapidement si Intel gênait de la concevoir un. P>
Voici ce que les autres réponses sont brillantes: cela dépend de l'architecture de la CPU au niveau du circuit réel. Les instructions de la machine font bouillir pour obtenir des données de quelque part, modifiez les données, chargez ou goto la prochaine instruction. p>
Pensez au problème comme un travailleur à bois qui travaille sur la construction ou la réparation d'une chaise pour vous. Ses questions seront "Où est la présidence", et "ce qui doit être fait à la chaise". Il pourrait être capable de le réparer chez vous ou qu'il pourrait avoir besoin de ramener la chaise à son magasin pour y travailler. De toute façon fonctionnera mais dépend de la préparation à laquelle il doit travailler en dehors d'un emplacement fixe. Cela pourrait le ralentir ou que ce soit sa spécialité. P>
Retour à la CPU. p>
Peu importe la manière dont une CPU parallèle peut être, comme ayant plusieurs adjoints ou pipelines de décodage d'instruction, ces circuits sont situés dans des emplacements spécifiques sur la puce et les données doivent être chargées dans les endroits où l'opération peut être effectuée. Le programme est chargé de déplacer les données dans et hors de ces emplacements. Dans une machine à base de piles, il peut fournir des instructions qui modifient directement les données, mais cela peut faire du ménage dans le microcode. Un additionneur fonctionne de la même manière, que les données provenaient de la pile ou du tas. La différence est dans le modèle de programmation disponible pour le programmeur. Les registres sont fondamentalement un lieu défini pour travailler sur les données. p> Analogie H2>
Explication H2>
Eh bien, eh bien il semble que la réponse à cela était également dans le livre (mise en œuvre moderne du compilateur en Java). Le livre présente 4 réponses: p>
Même sans aucune analyse interprététrique, si les procédures sont autorisées à «la corbeille», certains registres «gratter», mais sont tenus de préserver les autres, ont donc fourni suffisamment de registres, les routines de feuilles n'auront pas à sauver des registres (ils peuvent simplement utiliser «Scratch» Les «registres) et les routines non-feuilles utiliseront des registres non-rayures uniquement pour les valeurs qu'ils ont réellement besoin d'avoir préservé. Sauf si une fonction d'appels de boucle interne appelle deux profondes, il restera probablement de zéro registre enregistrer / restaurer les opérations dans la boucle interne.
Je pense que vous demandez pourquoi utiliser des registres, car les variables finissent par aller à la pile de toute façon. P>
La réponse est, pensez à des registres comme un cache pour les 5 ou 6 premiers éléments (ou autre) sur le dessus de la pile. Si le sommet de la pile est accessible beaucoup, beaucoup plus que le bas (ce qui est vrai dans de nombreux programmes), alors que ce cache accélérera les choses. P>
Je suppose que vous pourriez dire pourquoi avoir des registres visibles par l'utilisateur, au lieu d'une cache transparente des principaux bits. Je ne suis pas sûr, mais je suppose que laisser le compilateur savoir quelles valeurs seront en cache le permet d'optimiser davantage l'allocation de stockage. Après tout, s'il y a une certaine coupure dans la pile après quoi les accès variables seront beaucoup plus chers, vous organisez vos variables pour travailler avec cela. P>
Je ne comprends pas ce que vous entendez en sauvegarde et en restaurant ici, car vous êtes beaucoup trop vague sur quand cela se produit et pourquoi.
Caller-Sauvez les registres de Calle-Sauvegarder. Lorsque l'appelant appelle une fonction de calle, il peut choisir de mettre des valeurs (comme des variables ou des paramètres) dans des registres. S'il s'agit d'un enregistrement de sauvegarde de l'appelant - l'appelant doit prendre des mesures pour "enregistrer" la valeur avant d'appelle la "callee" et de les restaurer une fois que la "collance" revient.
Cependant, la plupart des programmes ont tendance à faire beaucoup de traitement dans des fonctions et ne dépensez pas tout leur temps à appeler et à revenir.
Vous ne pouvez pas laisser les valeurs sur la pile tout le temps, comme lorsque vous les transmettez dans la fonction, ils doivent être le haut de la pile, ainsi que dans une commande donnée, comme prévu par la fonction. Cela signifie que la complexité du paramètre qui passe est toujours là, même si vous n'utilisez pas de registres. Pour le rendre encore plus compliqué, vous pouvez parfois passer quelques arguments dans des registres.
La plupart des instructions du processeur (comme Ajout, multiplier ou comparer) ne peuvent pas fonctionner sur des adresses de mémoire générales, ce qui est bien sûr où se trouve la pile. C'est pourquoi vous devez d'abord déplacer la valeur en un registre. L'échange d'entrée / sortie est dû au flux du programme comme des appels de fonction où vous devez restaurer l'état de la CPU à votre retour.