7
votes

Un pointeur peut-il jamais indiquer un registre de la CPU?

Je me demande si un pointeur peut indiquer un registre de la CPU, car ce n'est peut-être pas, en utilisant la référence au lieu du pointeur, si possible donner une opportunité de compilateur à effectuer certaines optimisations car l'objet référencé peut résider dans un registre, mais une objet pointé par un pointeur peut ne pas.


9 commentaires

Cela dépend complètement de l'architecture de la machine sous-jacente, mais généralement la réponse est «non» pour la plupart des machines modernes, certainement x86.


Si vous demandez explicitement une variable d'être dans un registre, vous ne pouvez pas prendre son adresse.


Comme vous l'avez dit, l'optimisation serait effectuée par le compilateur. L'auteur d'un compilateur spécifique (devrait) savoir, si les pointeurs peuvent indiquer des registres sur l'architecture qu'il compile.


Hmm, un peu étrange que personne n'a mentionné le mot clé volatile ici. L'une des rares garanties qu'il offre, il devrait être sur le sujet. Peut-être que je manque quelque chose ici.


Un pointeur est un concept C / C ++, il n'existe pas dans le matériel. Et un registre n'existe que dans le matériel et C / C ++ ne sait rien de registres. Donc non, un pointeur ne peut jamais indiquer un registre de la CPU, car ils existent dans des mondes complètement séparés. :)


Un pointeur existe dans le matériel, appelé adressage indirect (ou d'autres noms en fonction de l'ISA), le registre détient l'adresse de l'élément d'intérêt et non de l'élément d'intérêt. Le langage C a été dérivé du jeu d'instructions PDP11, y compris l'incrément automatique (I ++;) et des pointeurs. Vous pouvez incrémenter les pointeurs pour passer d'une adresse à l'autre, etc. Utilisez l'adresse de pointeur / base pour un tableau, LDR R0, [R1, R2]. * D ++ = * s ++ ressemble à LDRB R0, [R1], # 1; STRB R0, [R2], # 1, etc.


@DWELCH: Ce que @jalf souligne correctement, c'est que C ++ est une langue, pas une mise en œuvre. Toute question comme "Les détails de mise en œuvre peuvent-ils déjà se produire en C ++?" est intrinsèquement absurde ou sans signification. C ++ ne Care à propos de X, de sorte que la langue est juste un hareng rouge.


@Gman Le commentaire était que, dans C / C ++, le concept d'un pointeur n'existe pas dans le matériel. C'est ce que je répondais. Le concept a été pris directement à partir du matériel et continue d'exister dans n'importe quel matériel utilisable. Je n'étais pas un concept créé par la langue mais une réalité que la langue mise en œuvre. Les structures, les syndicats, les booléens, les personnages, l'ajout signé, bien sûr, je suis d'accord avec cela, mais les pointeurs et les tableaux sont dérivés directement à partir de matériel.


@Dwelch: C'est vraiment une question de définition. Si vous suivez strictement la norme C, un "pointeur" n'est qu'un concept abstrait - la norme C ne prévoit pas comment un pointeur doit être mis en œuvre, et vous pouvez certainement écrire un compilateur C pour X86 qui n'utilise pas d'adressage indirect (à la place en utilisant des tables de recherche ou autre). D'autre part, C sur Course C'était conçu pour être facile à mettre en œuvre sur du matériel réel, bien sûr, les concepteurs de C pensaient de choses comme une adressage indirecte lorsqu'ils ont conçu la fonction de pointeur. Donc, vous avez tous deux raison, juste de différentes manières :-).


7 Réponses :


2
votes

Je pense que ce que vous vouliez dire, c'est si une valeur intégrale mentionnée par une référence réside dans un registre.

généralement, la plupart des compilateurs traitent des références de la même manière que les pointeurs. C'est-à-dire que des références ne sont que des pointeurs avec une sémantique spéciale «Dréréférence» intégrée. Donc, malheureusement, il n'ya généralement aucune optimisation contrairement aux valeurs intégrales pouvant s'intégrer dans des registres. La seule différence entre une référence et un pointeur est qu'une référence doit (mais non appliquée par le compilateur) se référer à un objet valide, alors qu'un pointeur peut être null.


0 commentaires

1
votes

Dans de nombreuses implémentations (sinon la plupart ou toutes), une référence est profonde à l'intérieur implémentée via un pointeur. Je pense donc que le faire via un pointeur ou une référence est à peu près pertinent pour un optimiseur.


0 commentaires

9
votes

En général, les registres de la CPU n'ont pas d'adresses de mémoire, bien qu'une architecture de la CPU puisse leur rendre adressable (je ne suis pas familière avec aucun - si quelqu'un en connaît un, j'apprécierais un commentaire). Cependant, il n'y a pas de manière standard dans C pour obtenir l'adresse d'un registre. En fait, si vous marquez une variable avec la classe de stockage Vous n'êtes pas autorisé à prendre cette adresse de variables à l'aide de l'opérateur & .

Le problème de la clé est un aliasing - si le compilateur peut déterminer qu'un objet n'est pas aliasé, il peut généralement effectuer des optimisations (si l'objet est accessible via un pointeur ou une référence). Je ne pense pas que vous obtiendrez un avantage d'optimisation en utilisant une référence sur un pointeur (en général de toute façon).

Toutefois, si vous copiez l'objet dans une variable locale, le compilateur peut permettre une détermination plus facile qu'il n'y a aucun aliasing de la section locale en supposant que vous ne passez pas l'adresse temporaire autour de vous. C'est un cas où vous pouvez aider le compilateur à optimiser; Toutefois, si l'opération de copie est chère, elle pourrait ne pas payer à la fin.

Pour quelque chose qui conviendrait dans un registre de la CPU, la copie à une température est souvent un bon moyen de partir - les compilateurs sont parfaits pour optimiser ceux qui se regorgent.


10 commentaires

Est-ce que la norme C ou C ++ disait explicitement qu'un registre déclaré objet ne peut pas être pris son adresse?


@Armen: Oui. @MichaelBurr: Les photos de microchip ont les registres de la CPU réels (par exemple l'état, le compteur de programmes, le registre de travail, les registres d'index) mappés sur les 12 octets inférieurs de chaque banque de mémoire. ww1.microchip.com/downloads/fr/devefetdoc/41413a.pdfle_/a > p. 23


@ARMEN - 6.5.3.2 Adresse et opérateurs indirectes: "L'opérande de l'opérateur de l'union et de l'opérateur doit être ... (un tas de choses qui s'appellent) ... ou un lvalue qui désigne un objet qui n'est pas un peu de bit et est non déclaré avec le spécificateur de classement de stockage de registre "


@Michael: Merci, je ne le connaissais jamais. Mais les compilateurs modernes mettent-ils un objet de registre dans un registre »parce que j'ai entendu dire qu'ils ignorent complètement l'indice d'enregistrement et décider de quoi faire un registre eux-mêmes


@ARMEN: J'ai également entendu parler de compilateur ignorant essentiellement le mot clé enregistrez lors de la détermination de la manière dont ils allouent des objets à des registres - la norme permet de certainement ce comportement. J'ai également entendu dire que vous ne devriez pas utiliser le mot clé, car vous allez gâcher le meilleur jugement du compilateur. Je ne suis pas sûr que l'extrême est plus vrai. La vérité est probablement que cela dépend du compilateur et des options que vous utilisez.


Chaque fois que j'ai essayé d'utiliser le mot-clé enregistrer avec compilateurs, j'utilise généralement (toutes les trucs MCU intégrés), ils l'ignorent simplement. Vous pouvez parfois forcer le problème avec l'assemblage intégré, mais les rares fois que j'ai essayé, je l'ai fait pire. Certains MCU, ce serait une blague, par ex. Le HCS08 dispose de 3 registres 8 bits ne comptant pas les pointeurs / comptoirs / status, mais vous pouvez utiliser des directives pour forcer l'allocation variable dans des parties plus rapides de RAM.


@ARMEN: Pour autant que je sache le seul avantage moderne au mot-clé de registre, il clarifie l'intention et en fait un bogue de prendre accidentellement l'adresse de l'objet. Donc, c'est une sorte d'utilisation de const.


Vous pouvez penser aux registres de Microchip Pic (PIC12, PIC16) comme une adresse également. La RAM / la mémoire est collectivement appelée le registre F. Et le code peut se référer à eux par leur adresse pour les registres spéciaux, le PC lui-même est adressable. Un processeur à base de pile comme le zpu opensource.zylin.com/zpu.htm où il n'y a pas de registres. N'ayons pas étudié le ZPU qui viennent de l'avoir vu et a rapidement vu que c'était une pile basée. Je veux dire le 8051 mais je ne peux pas le trouver dire que, je pense qu'il y a un autre que j'ai utilisé mais je ne me souviens pas.


@ Nick T, votre lien www1.microchip.com/downloads/fr/devefetdoc/41413a.pdf Affiche le fichier non trouvé. S'il vous plaît mettre à jour ça.


@Nickt: Lorsqu'il est appelé à -O0 , GCC utilisera le mot-clé enregistrez pour placer des objets dans des registres; Faire ceci soigneusement peut parfois permettre de fonctionner presque aussi bien qu'à des niveaux d'optimisation plus élevés, tout en restant compatible avec le code que l'optimiseur pause autrement.



0
votes

Pointeur pointe vers des emplacements de mémoire. Il n'est donc pas possible d'accéder aux registres de la CPU à l'aide de pointeurs. Les références sont une version moins puissante des pointeurs (vous ne pouvez pas effectuer d'arithmétiques sur des références). Cependant, les compilateurs mettent généralement des variables dans des registres pour effectuer des opérations. Par exemple, le compilateur peut mettre un compteur de boucle dans l'un des registres de la CPU pour un accès rapide. Ou peut mettre des paramètres de fonction qui ne prennent pas beaucoup d'espace dans des registres. Vous pouvez utiliser un mot clé que vous pouvez utiliser pour demander au compilateur de mettre certaines variables dans le registre de la CPU. Le mot-clé est registre : xxx


4 commentaires

Certaines architectures ont des registres mappés en mémoire, votre réponse n'est donc pas strictement correcte.


Le mot clé registre est essentiellement une demande creuse au compilateur qu'il est libre d'ignorer totalement et silencieusement.


@Paul r: Je suis d'accord. Mais je pense que c'est la solution la plus proche possible dans C.


@NICK T: Oui, j'ai déclaré dans le poteau: "... pour demander compilateur ..."



3
votes

Lorsqu'une référence est transmise à une fonction, le compilateur l'implémentera probablement en tant que pointeur caché - il est donc nécessaire de modifier le type.

Lorsqu'une référence est créée et utilisée localement, le compilateur peut être assez intelligent. Savoir ce qu'il fait référence et le traite comme un alias à la variable référencée. Si la variable est optimisée dans un registre, le compilateur saurait que la référence est également ce même registre. P>

Un pointeur devra toujours pointer sur un emplacement de mémoire. Même sur l'architecture étrange qui donne des emplacements de mémoire à ses registres, il semble peu probable que le compilateur supporte une telle opération. P>

EDIT: STRY> A titre d'exemple, voici le code généré. de Microsoft C ++ avec optimisations sur. Le code du pointeur et une référence passée sont identiques. Le paramètre transmis par la valeur pour une raison quelconque n'a pas fini dans un registre, même lorsque j'ai réorganisé la liste des paramètres. Malgré tout, une fois la valeur copiée à un registre à la fois la variable locale et la référence locale utilisée le même registre sans le recharger. P>

void __fastcall test(int i, int * ptr, int & ref)
{
_i$ = 8                         ; size = 4
_ref$ = 12                      ; size = 4
?test@@YIXHPAHAAH@Z PROC                ; test, COMDAT
; _ptr$ = ecx

; 8    :    global_int1 += *ptr;

    mov edx, DWORD PTR [ecx]

; 9    : 
; 10   :    global_int2 += ref;

    mov ecx, DWORD PTR _ref$[esp-4]
    mov eax, DWORD PTR _i$[esp-4]
    add DWORD PTR ?global_int1@@3HA, edx    ; global_int1
    mov edx, DWORD PTR [ecx]
    add DWORD PTR ?global_int2@@3HA, edx    ; global_int2

; 11   : 
; 12   :    int & ref2 = i;
; 13   :    global_int3 += ref2;

    add DWORD PTR ?global_int3@@3HA, eax    ; global_int3

; 14   : 
; 15   :    global_int4 += i;

    add DWORD PTR ?global_int4@@3HA, eax    ; global_int4


0 commentaires

0
votes

Michael Burr est correct. Les registres de la CPU n'ont pas d'adresses de mémoire.


2 commentaires

À moins qu'ils ne soient mappés à la mémoire, comme dans des photos de microchip


De plus, la Z8 avait des banques de registres mappés de mémoire IIRC.



1
votes

Je dirais généralement pas. Comme mentionné dans un commentaire ci-dessus, certains traitements sont des processeurs où vous pouvez adresser un registre dans l'espace mémoire, mais c'est probablement une mauvaise idée (à moins que la puce ne soit conçue pour que vous le programmiez de cette façon).

Cela ressemble plus au contraire de ce que vous demandez se produit effectivement. Les optimiseurs peuvent voir ce que vous faites avec un pointeur et ce qu'il pointe de l'architecture et en fonction de l'architecture peut ne pas utiliser un registre pour le pointeur et un registre pour contenir ce qu'il pointe, mais par exemple, peut être durcie à l'adresse Pas de registres du tout. Peut charger la valeur indiquée dans un registre mais utilisez un registre pour l'adresse ou l'utiliser plus longtemps que nécessaire pour obtenir la valeur. Parfois, ce n'est pas si efficace, il peut enregistrer la valeur dans un registre à la RAM pour que cela puisse la lire dans un registre à l'aide de son adresse, lors de la modification du code éviterait cette étape. Cela dépend fortement du programme / du code et du jeu d'instructions et du compilateur.

Donc, au lieu d'essayer de résoudre le registre pour essayer d'obtenir une optimisation, connaître le compilateur et la cible et savoir quand il est préférable d'utiliser des pointeurs ou des tableaux ou des valeurs, etc. Certaines constructions fonctionnent bien sur la plupart des processeurs et certains travaillent bien sur un mais mauvais sur les autres.


0 commentaires