Architectures exotiques dont se soucient les comités de normalisation

154

Je sais que les normes C et C ++ laissent de nombreux aspects de l'implémentation du langage définis simplement parce que s'il existe une architecture avec d'autres caractéristiques, il serait très difficile, voire impossible, d'écrire un compilateur conforme aux normes.

Je sais qu'il y a 40 ans, tout ordinateur avait sa propre spécification. Cependant, je ne connais aucune architecture utilisée aujourd'hui où:

  • CHAR_BIT != 8
  • signed n'est pas un complément à deux (j'ai entendu dire que Java avait des problèmes avec celui-ci).
  • La virgule flottante n'est pas conforme à la norme IEEE 754 (Edit: je voulais dire "pas dans l'encodage binaire IEEE 754").

La raison pour laquelle je pose la question est que j'explique souvent aux gens qu'il est bon que C ++ n'impose aucun autre aspect de bas niveau comme les types de taille fixe . C'est bien car contrairement aux `` autres langages '', cela rend votre code portable lorsqu'il est utilisé correctement (Edit: parce qu'il peut être porté sur plus d'architectures sans nécessiter d'émulation d'aspects de bas niveau de la machine, comme par exemple l'arithmétique du complément à deux sur l'architecture signe + magnitude) . Mais je me sens mal de ne pouvoir désigner moi-même aucune architecture spécifique.

La question est donc: quelles architectures présentent les propriétés ci-dessus?

uint*_ts sont facultatifs.

Yakov Galka
la source
9
Je pense que vous l'avez à l'envers. Si le C ++ imposait, disons, un complément de deux pour les entiers signés, il rendrait le code C ++ plus portable, pas moins. La question de savoir pourquoi le comité des normes C ++ n'impose pas cela est une autre question. D'autant que, malgré ce que vous dites, il ne serait pas impossible d'écrire un compilateur pour une architecture non standard, vous pouvez toujours simuler des caractères 8 bits ou deux en complément de l'arithmétique même lorsque votre plateforme ne la supporte pas directement.
john
8
@john: alors ce ne serait pas pratique, donc un compilateur conforme non standard générerait un code plus rapide qu'un compilateur conforme. Et je ne vois toujours pas comment cela rend votre code plus portable.
Yakov Galka
4
Je suis sûr que la vraie raison pour laquelle la norme est telle n'est pas parce que c'est une solution idéale. Mais c'est plutôt parce que lorsque le standard a été écrit, de nombreux compilateurs C et C ++ existaient déjà, et le comité des normes ne voulait pas rejeter les compilateurs existants.
john
4
@john: Je doute que "faciliter la tâche aux rédacteurs de compilateurs" soit une priorité lors de la création du standard C ++ (ils feraient un travail terrible si c'était le cas, puisque C ++ est l'un des langages les plus difficiles à analyser, et d'autres aspects de le langage ne facilite pas non plus la tâche des auteurs de compilateurs). Les performances, la prise en charge d'une large plate-forme et la compatibilité descendante sont cependant assez importantes. Et tous ces trois souffriraient si la ou les restrictions que vous mentionnez étaient ajoutées à la norme.
Sander De Dycker
5
Il ne s'agit pas du compilateur mais du matériel. C ++ laisse certaines choses non spécifiées pour permettre l'utilisation directe des fonctionnalités matérielles. De toute façon, les applications de votre téléphone ne fonctionneront pas sur un ordinateur central, il n'y a donc pas de portabilité, quelle que soit la conformité du code.
Bo Persson

Réponses:

114

Jetez un œil à celui-ci

Serveurs Unisys ClearPath Dorado

offrant une rétrocompatibilité pour les personnes qui n'ont pas encore migré tous leurs logiciels Univac.

Points clés:

  • Mots de 36 bits
  • CHAR_BIT == 9
  • son complément
  • Virgule flottante non IEEE 72 bits
  • espace d'adressage séparé pour le code et les données
  • adressé par mot
  • pas de pointeur de pile dédié

Je ne sais pas s'ils proposent un compilateur C ++, mais ils le pourraient .


Et maintenant, un lien vers une édition récente de leur manuel C est apparu:

Manuel de référence de programmation du compilateur Unisys C

La section 4.5 a un tableau des types de données avec 9, 18, 36 et 72 bits.

taille et plage des types de données dans le compilateur USC C

Bo Persson
la source
13
Je suppose que void * doit être infernal à utiliser dans cette architecture.
luiscubal
13
@ybungalobill - Je crois char*et void*doit être de la même taille et suffisamment grand pour contenir n'importe quel autre pointeur. Le reste dépend de la mise en œuvre.
Bo Persson
22
@ybungalobill: Sur les anciens compilateurs Win16, les pointeurs réguliers étaient des pointeurs proches et ne contenaient qu'un décalage de 16 bits, donc sizeof(int*) == 2, mais les pointeurs éloignés avaient également un sélecteur 16 bits, donc sizeof(void*) == 4.
Adam Rosenfield
10
Il existe, ou a déjà existé, un manuel en ligne pour leur compilateur C ++. Il convient également de souligner qu'il ne s'agit que de l'une des architectures mainframe Unisys: l'autre est une architecture étiquetée en magnitude signée 48 bits (pour laquelle je n'ai trouvé qu'un manuel C, pas un C ++). Concernant le reste: je ne pense pas que sizeof(int*) != sizeof(char*)ici: les deux sont 36 bits. Mais le sélecteur d'octets dans le char*est sur les bits de poids fort et est ignoré dans int*. (J'ai utilisé d'autres machines, cependant, où `sizeof (char *)> sizeof (int *).)
James Kanze
16
@Adam Rosenfield Sur les compilateurs MS / DOS 16 bits, vous aviez différents "modes" et les pointeurs de données n'étaient pas nécessairement de la même taille que les pointeurs de fonction. Mais au moins sur ceux que j'ai utilisés, tous les pointeurs de données (y compris void*) avaient toujours la même taille. (Bien sûr, vous ne pouvez pas convertir un pointeur de fonction en void*, car il void*peut être plus petit. Mais selon la norme, vous ne pouvez pas non plus le faire aujourd'hui.)
James Kanze
51

Aucune de vos hypothèses ne vaut pour les mainframes. Pour commencer, je ne connais pas de mainframe qui utilise IEEE 754: IBM utilise la base 16 en virgule flottante, et les deux mainframes Unisys utilisent la base 8. Les machines Unisys sont un peu spéciales à bien d'autres égards: Bo a mentionné le 2200 architecture, mais l'architecture MPS est encore plus étrange: mots balisés de 48 bits. (Que le mot soit un pointeur ou non dépend d'un peu du mot.) Et les représentations numériques sont conçues pour qu'il n'y ait pas de réelle distinction entre l'arithmétique à virgule flottante et intégrale: la virgule flottante est en base 8; il ne nécessite pas de normalisation, et contrairement à tous les autres points flottants que j'ai vus, il place la décimale à droite de la mantisse, plutôt qu'à gauche, et utilise une magnitude signée pour l'exposant (en plus de la mantisse). Avec les résultats qu'une valeur à virgule flottante intégrale a (ou peut avoir) exactement la même représentation en bits qu'un entier de magnitude signé. Et il n'y a pas d'instructions arithmétiques à virgule flottante: si les exposants des deux valeurs sont tous les deux 0, l'instruction fait de l'arithmétique intégrale, sinon, elle fait de l'arithmétique à virgule flottante. (Une continuation de la philosophie de marquage dans l'architecture.) Ce qui signifie que toutint peut occuper 48 bits, 8 d'entre eux doivent être 0 ou la valeur ne sera pas traitée comme un entier.

James Kanze
la source
4
Les mainframes IBM (z / Architecture) prennent en charge la virgule flottante IEE754.
Nikita Nemkin
1
Pour info voir ce commentaire twitter
Shafik Yaghmour
6
@Nikita - Ils le font maintenant . Au départ, c'était un add-on (coûteux) pour prendre en charge Java.
Bo Persson
42

La conformité totale IEEE 754 est rare dans les implémentations en virgule flottante. Et affaiblir la spécification à cet égard permet de nombreuses optimisations.

Par exemple, le support subnorm diffère entre x87 et SSE.

Les optimisations comme la fusion d'une multiplication et d'une addition qui étaient séparées dans le code source modifient légèrement les résultats aussi, mais c'est une belle optimisation sur certaines architectures.

Ou sur x86, la conformité IEEE stricte peut nécessiter la définition de certains indicateurs ou des transferts supplémentaires entre les registres à virgule flottante et la mémoire normale pour le forcer à utiliser le type à virgule flottante spécifié au lieu de ses flottants internes de 80 bits.

Et certaines plates-formes n'ont aucun flotteur matériel et doivent donc les émuler dans le logiciel. Et certaines des exigences de la norme IEEE 754 peuvent être coûteuses à implémenter dans les logiciels. En particulier, les règles d'arrondi pourraient poser problème.

Ma conclusion est que vous n'avez pas besoin d'architectures exotiques pour entrer dans des situations où vous ne voulez pas toujours garantir une conformité IEEE stricte. Pour cette raison, peu de langages de programmation garantissent une stricte conformité IEEE.

CodesInChaos
la source
7
Les mainframes IBM, dont le format à virgule flottante est antérieur à la norme IEEE, constituent un autre ensemble de matériel «exotique». Contrairement à Java, C ++ peut toujours utiliser le matériel existant.
Bo Persson
5
IEEE 754 n'est pas entièrement pris en charge par les GPU.
kerem
3
Le manque de conformité stricte à la norme IEEE 754 est un problème pour certains, mais je ne pense pas que ce soit tout à fait dans la portée des problèmes qui préoccupent vraiment l'OP.
Omnifarious
3
@Matthieu Comme il est également étiqueté "C", je devrais mentionner un analyseur C qui peut vous indiquer toutes les valeurs que votre programme à virgule flottante peut prendre avec des registres à virgule flottante de 80 bits déversés en mémoire au gré du compilateur C. blog.frama-c.com/index.php?post/2011/03/03/cosine-for-real
Pascal Cuoq
2
@MatthieuM .: C'est dommage que l'ISO / ANSI n'ait pas permis aux paramètres variadiques de spécifier des tailles minimum / maximum pour les arguments à virgule flottante et entiers; s'ils l'avaient fait, le 80 bits long doubleaurait pu être un type utile et durable, car le seul vrai problème avec lui était qu'il fonctionne mal avec printf. Le fait que le double étendu stocke le premier 1 accélère explicitement les calculs sur les systèmes non FPU et éliminerait également le besoin de traitement spécial des dénormalités dans tout contexte autre que les conversions vers / à partir d'autres types. Dommage que C ait printftout gâché.
supercat
40

J'ai trouvé ce lien répertoriant certains systèmesCHAR_BIT != 8. Ils comprennent

certains DSP TI ont CHAR_BIT == 16

Puce BlueCore-5 (une puce Bluetooth de Cambridge Silicon Radio) qui a CHAR_BIT == 16.

Et bien sûr, il y a une question sur Stack Overflow: quelles plates-formes ont autre chose que le caractère 8 bits

En ce qui concerne les systèmes non complémentaires à deux, il y a une lecture intéressante sur comp.lang.c ++. Modérée . En résumé: il existe des plates-formes ayant un complément ou une représentation de signe et de grandeur.

dcn
la source
5
Analog Devices 32 bits SHARC DSP a CHAR_BIT=32, et Texas Instruments DSP de TMS32F28xx a CHAR_BIT=16. GCC 3.2 pour PDP-10 a CHAR_BIT=9. Je pense que S / 360 peut aussi avoir un caractère non 8 bits.
osgx
1
Je voudrais encore un exemple pour les architectures «complément de non deux». D'autant plus qu'il est arrivé que le CHAR_BITSsoit un duplicata partiel.
Yakov Galka
Les DSP TI ont des caractères 16 bits uniquement parce que les implémenteurs l'ont choisi (ce serait un peu plus de travail pour le faire fonctionner correctement, mais pas absurdement difficile IIRC - probablement juste quelques «trous» dans l'échafaudage de codegen dans le compilateur sous-jacent) . Ce n'est donc pas une raison architecturale profonde. Le code C fonctionne sur une machine abstraite. Si tout ce que vous avez est des INT de 16 bits, stockez deux caractères dans chacun, et ajoutez la fusion en lecture-modification-écriture à l'optimiseur de judas (au moins). Bien sûr, c'est plus de travail, mais regardez combien il y a de travail supplémentaire pour tout le monde pour faire face à des types aussi étranges dans des endroits où ils ne se présenteront jamais. Beurk.
Réintégrer Monica le
24

Je suis assez sûr que les systèmes VAX sont toujours utilisés. Ils ne prennent pas en charge la virgule flottante IEEE; ils utilisent leurs propres formats. Alpha prend en charge les formats à virgule flottante VAX et IEEE.

Les machines vectorielles Cray, comme le T90, ont également leur propre format à virgule flottante, bien que les nouveaux systèmes Cray utilisent IEEE. (Le T90 que j'ai utilisé a été mis hors service il y a quelques années; je ne sais pas s'il y en a encore en cours d'utilisation.)

Le T90 avait également des représentations intéressantes pour les pointeurs et les entiers. Une adresse native ne peut pointer que sur un mot de 64 bits. Les compilateurs C et C ++ avaient CHAR_BIT == 8 (nécessaire car il exécutait Unicos, une version d'Unix, et devait interagir avec d'autres systèmes), mais une adresse native ne pouvait pointer que sur un mot de 64 bits. Toutes les opérations de niveau octet ont été synthétisées par le compilateur, et a void*ou char*stocké un décalage d'octet dans les 3 bits de poids fort du mot. Et je pense que certains types entiers avaient des bits de remplissage.

Les mainframes IBM sont un autre exemple.

D'un autre côté, ces systèmes particuliers ne doivent pas nécessairement empêcher des modifications de la norme linguistique. Cray n'a montré aucun intérêt particulier pour la mise à niveau de son compilateur C vers C99; probablement la même chose appliquée au compilateur C ++. Il peut être raisonnable de resserrer les exigences pour les implémentations hébergées, comme exiger CHAR_BIT == 8, virgule flottante au format IEEE sinon la sémantique complète, et complément à 2 sans bits de remplissage pour les entiers signés. Les anciens systèmes pourraient continuer à prendre en charge les normes de langage antérieures (C90 n'est pas mort lorsque C99 est sorti), et les exigences pourraient être plus lâches pour les implémentations autonomes (systèmes embarqués) tels que les DSP.

D'un autre côté, il pourrait y avoir de bonnes raisons pour que les futurs systèmes fassent des choses qui seraient aujourd'hui considérées comme exotiques.

Keith Thompson
la source
6
Bon point à la fin sur la façon dont des normes trop strictes empêchent l'innovation. Lorsque nous obtenons des ordinateurs quantiques (ou organiques) avec des états trinaires, les exigences arithmétiques modulo pour unsignedles types intégraux seront une douleur majeure, tandis que l'arithmétique signée sera très bien.
Ben Voigt
@BenVoigt Pourquoi cette arithmétique non signée est-elle pénible? Les additionneurs modulo 3 ^ n dans ces ordinateurs ne sont-ils pas possibles?
phuclv
2
@ LưuVĩnhPhúc: C'est exactement le but, avec des opérations matérielles effectuées modulo 3 ** n, fournir des types non signés C ++ dont les opérations sont définies modulo 2 ** n sera difficile.
Ben Voigt
2
Je connais un VAX 11/780 encore utilisé comme hôte pour un compilateur croisé ciblant un système embarqué spécialisé avec une architecture propriétaire. Pour soutenir ce VAX particulier, les gardiens ont approché les musées pour des pièces de rechange.
Peter
2
@Keith - techniquement, le seul obstacle est de passer par un processus pour fournir des preuves qui satisferont aux exigences réglementaires, car le système embarqué cible est de haute criticité. Il existe cependant de nombreux obstacles non techniques (politique organisationnelle, etc.) qui, à ce jour, ont été insurmontables. Actuellement, il est plus facile de monter un cas pour piller les musées que de mettre à jour l'hôte.
Peter
16

CHAR_BITS

Selon gcc code source :

CHAR_BITest des 16bits pour les architectures 1750a , dsp16xx .
CHAR_BITest des 24bits pour l' architecture dsp56k .
CHAR_BITest des 32bits pour c4x architecture .

Vous pouvez facilement en trouver plus en faisant:

find $GCC_SOURCE_TREE -type f | xargs grep "#define CHAR_TYPE_SIZE"

ou

find $GCC_SOURCE_TREE -type f | xargs grep "#define BITS_PER_UNIT"

si CHAR_TYPE_SIZEest correctement défini.

Conformité IEEE 754

Si l'architecture cible ne prend pas en charge les instructions en virgule flottante, gcc peut générer un logiciel de secours qui n'est pas conforme à la norme par défaut. De plus, des options spéciales (comme la -funsafe-math-optimizationssorcière désactive également la préservation des signes pour les zéros) peuvent être utilisées.

Ivaigult
la source
3
voté pour avoir simplement demandé à l'OP de regarder la source d'un compilateur populaire; c'est la définition de RFTM dans ce cas, donc ce devrait être le premier endroit où les gens regardent.
underscore_d
9

La représentation binaire IEEE 754 était rare sur les GPU jusqu'à récemment, voir GPU Floating-Point Paranoia .

EDIT: une question a été soulevée dans les commentaires si la virgule flottante GPU est pertinente pour la programmation informatique habituelle, sans rapport avec les graphiques. Putain, oui! La plupart des éléments de haute performance calculés industriellement aujourd'hui se font sur des GPU; la liste comprend l'IA, l'exploration de données, les réseaux neuronaux, les simulations physiques, les prévisions météorologiques et bien plus encore. L'un des liens dans les commentaires montre pourquoi: un ordre de grandeur avantage en virgule flottante d' des GPU.

Une autre chose que je voudrais ajouter, qui est plus pertinente à la question OP: qu'ont fait les gens il y a 10-15 ans quand la virgule flottante GPU n'était pas IEEE et quand il n'y avait pas d'API comme OpenCL ou CUDA d'aujourd'hui pour programmer les GPU? Croyez-le ou non, les premiers pionniers de l'informatique GPU ont réussi à programmer des GPU sans API pour le faire ! J'en ai rencontré un dans ma société. Voici ce qu'il a fait: il a encodé les données dont il avait besoin pour calculer comme une image avec des pixels représentant les valeurs sur lesquelles il travaillait, puis a utilisé OpenGL pour effectuer les opérations dont il avait besoin (comme le "flou gaussien" pour représenter une convolution avec une distribution normale , etc.) et a décodé l'image résultante en un tableau de résultats. Et c'était encore plus rapide que d'utiliser le processeur!

C'est ce qui a poussé NVidia à rendre enfin ses données binaires internes compatibles avec IEEE et à introduire une API orientée sur le calcul plutôt que sur la manipulation d'images.

Michael
la source
Quelle est la pertinence des GPU? (a) Cette page semble très obsolète. (b) Jusqu'à ce jour, vous ne pouvez pas programmer de GPU en C: parce que C prend en charge des éléments tels que les fonctions récursives que les GPU, à ma connaissance, ne font pas. Vous ne pouvez donc même pas écrire un compilateur si vous le souhaitez.
Yakov Galka
1
@ybungalobill, le déchargement du travail répétitif sur le GPU est actuellement la méthode préférée pour les calculs à grande échelle . En fait, j'en développe actuellement un en C ++. Heureusement, nous ne travaillons qu'avec des GPU NVidia CUDA qui ont une représentation binaire compatible IEEE 754 des flottants.
Michael
Je ne dis pas que les GPU ne sont pas utilisés pour les calculs GP. J'ai dit que vous ne programmez pas vraiment les noyaux en C, malgré la similitude de syntaxe. Pouvez-vous exécuter int f(int n) { return n <= 1 ? 1 : n * f(n-1); }dans CUDA? Si non, les GPU ne sont pas pertinents pour cette question (qui concerne les comités C et C ++).
Yakov Galka
6
@ybungalobill: plusieurs réponses à cela. Premièrement, CUDA prend en charge C, C ++ et Fortran . Voir le même lien pour l'énorme avantage de performances des GPU à 2048 threads par rapport à votre CPU 8 threads typique. Deuxièmement, il est vrai que seuls les sous-ensembles (bien que les plus grands) de ces langages sont pris en charge, y compris le manque de support pour la récursivité appropriée pour le modèle de programmation CUDA (appelé «parallélisme dynamique») jusqu'à CUDA 5.0. Troisièmement, les récursions peuvent généralement être remplacées par des boucles, ce qui est de toute façon nécessaire pour les performances multithreads.
Michael