Comment les langues ont-elles influencé la conception du processeur? [fermé]

44

On nous dit souvent que le matériel ne tient pas compte de la langue dans laquelle un programme est écrit, car il ne voit que le code binaire compilé, mais ce n'est pas toute la vérité. Par exemple, considérons l'humble Z80; ses extensions du jeu d'instructions 8080 incluent des instructions telles que CPIR, ce qui est utile pour balayer des chaînes de style C (terminées par NULL), par exemple pour les effectuer strlen(). Les concepteurs doivent avoir identifié le fait que l'exécution de programmes en C (par opposition à Pascal, où la longueur d'une chaîne de caractères est dans l'en-tête) était susceptible de servir à leur conception. Un autre exemple classique est la machine Lisp .

Quels autres exemples y a-t-il? Par exemple, les instructions, le nombre et le type de registres , les modes d'adressage, qui permettent à un processeur particulier de préférer les conventions d'un langage particulier? Je suis particulièrement intéressé par les révisions de la même famille.

Gaius
la source
3
N'oubliez pas que le Z-80 disposait également de l'instruction LDIR, très utile lors de la copie de chaînes lorsque vous connaissez la longueur (comme en Pascal, où la longueur était stockée dans l'en-tête).
TMN
27
1. Le Z-80 a été conçu en 1975, alors qu’Unix et C étaient un système d’exploitation et un langage obscurs sur quelques ordinateurs, trois ans avant la première édition de K & R. 2. Rien dans Pascal n’exige que la longueur de la chaîne soit "dans un en-tête". 3. Les chaînes dans CP / M, le système d'exploitation principal du micro-ordinateur à l'époque, se terminaient par le caractère '$' et non par '\ 0'. CPIR peut rechercher n'importe quel caractère. 4. CPIR est associé à CPDR (recherche en arrière), ainsi qu'à d'autres instructions -IR et -DR. Conclusion: CPIR n’a rien à voir avec le langage de programmation C. C'est juste une instruction de recherche d'octet.
librik
4
Le plus gros (et l'un des plus ennuyeux pour les concepteurs de matériel) des choses forcées par C est un adressage d'octet. Les processeurs auraient été plus simples et plus rapides sans cette abomination.
SK-logic le
1
@ SK-logic: Bien que la norme POSIX nécessite un adressage sur des octets, la norme C n'en nécessite pas. Toute implémentation où sizeof(int)égal à 1 doit obliger ce type à charêtre signé (car il intdoit pouvoir contenir toutes les valeurs de type char). J'ai écrit du code pour une machine où charet intsont tous deux des entiers signés 16 bits; Les plus grandes difficultés sont qu’il est impossible d’utiliser des unions pour la conversion de types et que, pour stocker efficacement un grand nombre d’octets, il est nécessaire d’emballer et de décompresser manuellement. Ces problèmes sont mineurs comparés à la possibilité en C que sizeof (int) == sizeof (long), depuis ...
supercat
2
... cela signifie qu'il n'y a pas de type standard garantissant la différence entre deux unsigned intvaleurs. C99 a amélioré cette situation, mais avant C99, il n'existait aucune méthode sécurisée en une étape pour comparer une valeur potentiellement négative à une valeur de type unsigned int(il faudrait vérifier si le nombre était négatif avant de faire la comparaison).
Supercat

Réponses:

20

Les réponses existantes se concentrent sur les modifications d' ISA . Il y a aussi d'autres modifications matérielles. Par exemple, C ++ utilise couramment vtables pour les appels virtuels. À partir du Pentium M , Intel intègre un composant "prédicteur de branche indirecte" qui accélère les appels de fonctions virtuelles.

MSalters
la source
6
Et l'architecture RISC de Berkeley incluait le concept de "fichier de registre". Ainsi, au lieu de créer des registres de "fonctions" sur la pile, un bloc de 8 registres était attribué à chaque fonction. Ce code orienté objet très rapide a tendance à se composer de nombreux appels de méthodes à des méthodes courtes.
TMN
1
Ce n'est pas un exemple valable. La conception "Tableau de pointeurs de fonction" est également utilisée dans de nombreux scénarios de liaison dynamique, par exemple via l'importation et l'exportation de DLL sous Windows, ainsi que dans les programmes C. Bien que je suppose que vous puissiez dire que cela montre que le processeur est optimisé pour une utilisation spécifique, ce n'est pas spécifique à la langue.
DeadMG
@DeadMG: D'autres cas ont bénéficié, c'est vrai. Mais jusqu'à ce que le C ++ devienne populaire, les conceptions de CPU n'étaient pas influencées . Et c'était la question posée. De même, le RGT a un point à propos des fichiers de registre. L'Assemblée n'avait pas un concept aussi clair de fonctions. Les fonctions, telles que nous les comprenons aujourd'hui, remontent à Algol 60 et nous pouvons donc affirmer qu'Algol 60 a influencé la conception du fichier de registre de la CPU.
MSalters
14

Le jeu d’instructions Intel 8086 inclut une variante de "ret" qui ajoute une valeur au pointeur de pile après l’ ajout de l’adresse de retour. Ceci est utile pour de nombreuses implémentations Pascal où l'appelant d'une fonction va placer des arguments sur la pile avant de faire un appel de fonction et les extraire ensuite. Si une routine accepte, par exemple, une valeur de quatre octets de paramètres, elle pourrait se terminer par "RET 0004" pour nettoyer la pile. En l'absence d'une telle instruction, une telle convention d'appel aurait probablement obligé le code à afficher l'adresse de retour dans un registre, à mettre à jour le pointeur de pile, puis à accéder à ce registre.

Il est intéressant de noter que la plupart des codes (y compris les routines de système d'exploitation) du Macintosh d'origine ont utilisé la convention d'appel Pascal malgré l'absence d'instruction de facilitation dans le 68000. L'utilisation de cette convention d'appel a permis d'économiser 2 à 4 octets de code sur un site 4-6 octets de code sur le site de retour de chaque fonction prenant des paramètres.

supercat
la source
Il y a aussi une ENTERcontrepartie à cette RET n...
Herby
1
@herby: Je ne pense pas qu'il ENTERexistait dans l'original 8086; il est venu avec les processeurs ultérieurs. Cela soulève toutefois un point intéressant: les modes d’adressage basés sur le tiers sont clairement conçus en fonction de l’utilisation de paramètres empilés et de paramètres locaux empilés via un pointeur de trame. Je trouve cette convention intéressante à plusieurs égards, en particulier si l’on considère que (1) le code en langage assembleur pur est plus apte à utiliser les valeurs dans les registres que la pile, mais (2) les avantages de l’adressage [BP + nn] par rapport à [SP + nn] les adresses sont plus importantes pour les programmes en langage assembleur qui accèdent à des éléments de la pile que ...
supercat
... pour le code d'assemblage écrit à la main. Un compilateur sait généralement, pour chaque instruction générée, comment SP et BP se comparent; Si SP est BP-8, par exemple, il n'est pas vraiment plus facile pour le compilateur d'adresser [BP + 12] que [SP + 20]. Si, lors d'une recompilation, le compilateur doit ajouter un autre code PUSH / POP autour d'un bloc de code, il peut ajuster les décalages basés sur SP de manière appropriée. D'autre part, dans un assemblage écrit à la main, l'ajout d'un fichier PUSH / POP nécessiterait probablement de modifier le code entre eux. Ainsi, les pointeurs de trame sont principalement un avantage pour le code de haut niveau / asm combiné.
Supercat
Peut-être qu'une possibilité de réutiliser du code sans sa recompilation constitue également un point d'utilisation marginal pour l'adressage BP. Et Dieu sait si les instructions d'adressage de BP ne sont pas plus rapides dans le circuit que celles adressées de SP, car l'adressage de BP est en quelque sorte standard ...
Herby August
3
@herby: En fait, je soupçonne qu'une grande partie de la raison pour laquelle les compilateurs utilisent généralement les pointeurs de trames a beaucoup à voir avec le débogage. Pour déboguer un programme qui n'utilise pas une telle convention, il faudrait que le compilateur génère - et que le débogueur utilise - un fichier répertoriant le décalage SP-BP pour chaque instruction. De telles métadonnées détaillées sont courantes aujourd'hui (et constituent une partie essentielle de ce qui rend pratiques les langages collectés avec ordures), mais la quantité de RAM requise aurait été inacceptable il y a 30 ans.
Supercat
10

Un exemple est MIPS, qui a les deux addet addupour piéger et ignorer les débordements, respectivement. (Aussi subet subu.) Il avait besoin du premier type d’instruction pour les langues comme Ada (je pense que je n’ai jamais utilisé Ada), qui traitent explicitement des débordements et du second type pour les langues comme C qui les ignorent.

Si je me souviens bien, le processeur réel dispose de circuits supplémentaires dans l'ALU pour suivre les débordements. Si le seul langage qui importait était le C, il n'aurait pas besoin de ça.

Tikhon Jelvis
la source
Vous ne savez pas vraiment si elles sont liées, mais ces instructions sont probablement utiles dans d'autres situations, telles que l'allocation de mémoire sécurisée, c'est-à-dire si vous allouez des nmemb*size+offsetoctets et que vous devez vous assurer que vous n'obtenez pas un dépassement de capacité.
NikiC
@NikC: Je pensais que les instructions adduet subu(celles qui ne vérifient pas les débordements) sont celles qui ont été ajoutées pour rendre C heureux. Bien sûr, je ne sais pas vraiment - nous l’avons seulement couvert de manière vague et je ne suis certainement pas un expert en architecture: P.
Tikhon Jelvis
Oh oui, je pensais dans l'autre sens, désolé: /
NikiC
8

La série Burroughs 5000 a été conçue pour prendre en charge efficacement ALGOL et le processeur Intel iAPX-432 a été conçu pour exécuter efficacement Ada. Le transputeur Inmos avait son propre langage, Occam. Je pense que le processeur "Propeller" de Parallax a été conçu pour être programmé à l'aide de sa propre variante de BASIC.

Ce n'est pas un langage, mais le jeu d'instructions VAX-11 contient une seule instruction pour charger un contexte de processus, qui a été conçu à la suite d'une demande de l'équipe de conception de VMS. Je ne me souviens pas des détails, mais ISTR nécessitait tellement d'instructions à mettre en œuvre que cela limitait sérieusement le nombre de processus pouvant être planifiés.

RGT
la source
Qu'est-ce qui rend ces modèles particulièrement adaptés à ces modèles? Par exemple, de quelle caractéristique de l'iAPX Ada bénéficie-t-il particulièrement?
Gaius
ISTR que la cible Ada de l'iAPX-432 essayait plus de sauver un dessin qui avait échoué en le rattachant à quelque chose avec encore de grandes attentes qu'autre chose.
AProgrammer
@AProgrammer: Je suis à peu près sûr que l'iAPX-432 a été conçu dès le départ pour utiliser Ada. Je me souviens même de rumeurs selon lesquelles Intel n’allait pas publier le jeu d’instructions pour décourager la programmation en langage assembleur et forcer les utilisateurs à utiliser Ada pour tout.
TMN
1
@TMN, le projet Intel 432 a été lancé en 1975 et introduit en 1981 (Wikipedia). Ironman (exigences finales pour Ada) a été publié en janvier 1977 et le vert choisi en mai 1979, modifié et le résultat final publié en tant que norme militaire en juillet 1980. Il existe un problème de chronologie indiquant que l'iAPX-432 a été conçu à partir le début d'utiliser Ada. (Il s’agit d’un processeur tardif et typique, "comble le fossé sémantique", qui présente les inconvénients habituels à une époque où on commençait à chercher des alternatives; le commercialiser sous le nom de processeur Ada était une tentative de sauvegarde d’un concept échoué - ISTR que seul Intel utilisait. )
AProgrammer
1
@AProgrammer: Hmmm, on dirait que tu as raison. Je suis tombé sur ce document émanant de l'architecte principal du 432 et dans le résumé, il déclare: "Cette correspondance étroite entre l'architecture et le langage ne s'est pas produite, car le 432 était conçu pour exécuter Ada. Ce n'était pas le cas." Je vais devoir extraire mon vieux livre 432 et voir ce qu'il dit.
TMN
8

Une chose que personne ne semble avoir mentionnée jusqu’à présent est que les progrès en matière d’optimisation du compilateur (où le langage de base est en grande partie hors de propos) ont entraîné le passage des jeux d’instructions CISC (qui étaient en grande partie conçus pour être codés par des humains) aux jeux d’instructions RISC (qui étaient largement conçu pour être codé par les compilateurs.)

rockets4kids
la source
5

La famille Motorola 68000 a introduit un mode d’ adresse automatique qui rend la copie de données via le processeur très efficace et compacte.

[Exemple mis à jour]

c'était un code c ++ qui a influencé l'assembleur 68000

while(someCondition)
    destination[destinationOffset++] = source[sourceOffset++]

implémenté en assembleur classique (pseudocode, j'ai oublié les commandes de l'assembleur 68000)

adressRegister1 = source
adressRegister2 = destination
while(someCondition) {
    move akku,(adressRegister1)
    move (adressRegister2), akku
    increment(adressRegister1, 1)
    increment(adressRegister2, 1)
}

avec la nouvelle adresse, il est devenu quelque chose de similaire à

adressRegister1 = source
adressRegister2 = destination
while(someCondition) {
    move akku,(adressRegister1++)
    move (adressRegister2++), akku
}

seulement deux instructions par boucle au lieu de 4.

k3b
la source
1
Comment cela a-t-il été influencé par les conventions d'une langue particulière?
Gaius
voir l'exemple mis à jour
k3b le
Ah, ça me rappelle l'optimisation de la boucle DBxx dans le 68010.
Gaius
7
En fait, je pense que vous avez cela à l'envers. L’adressage automatique [incrémentation] faisait partie du jeu d’instructions PDP-11, ce qui a probablement influencé la conception de C.
TMN,
5

Le mainframe de la série Z d’IBM est le descendant de l’IBM 360 des années 1960.

Plusieurs instructions ont été mises en place pour accélérer les programmes COBOL et Fortran. L'exemple classique étant le BXLE- "Branch on Index Low Or Equal", qui est la plupart du temps une forboucle Fortran ou un COBOL PERFORM VARYING x from 1 by 1 until x > nencapsulé dans une seule instruction.

Il existe également toute une famille d'instructions décimales condensées destinées à prendre en charge l'arithmétique décimale à virgule fixe commune aux programmes COBOL.

James Anderson
la source
Je pense que vous voulez dire descendant .
Clockwork-Muse
@ X-Zero - oups! Tôt le matin, pas assez de café dans le système, etc .......
James Anderson
1
Plus intéressante est l'instruction de répétition de bloc de la TI 32050 DSP. Son opérande est l'adresse de l'instruction suivant le dernier de la boucle; le chargement d'un registre de comptage de boucles, puis l'exécution de l'instruction block-repeat entraîneront la répétition des instructions jusqu'à la cible (sans l'inclure) le nombre de fois spécifié. Cela rappelle fortement une DOboucle FORTRAN .
Supercat
@supercat Chaque DSP digne de ce nom comporte trois caractéristiques: une boucle sans overhead, une instruction simple multiplier-accumuler et un mode d'adressage inversé sur un bit. Presque tous les algorithmes DSP connus de Man utilisent des boucles. Les deux algorithmes les plus courants sont le filtre FIR, qui est une boucle entourant une multiplication-accumulation, et la FFT, pour laquelle l'adressage à inversion de bits est essentiel. De nombreux DSP incluent une opération papillon FFT à une instruction - 2 ou une multiplication / addition double pouvant être utilisée pour créer un papillon à une instruction.
John R. Strohm
@ JohnR.Strohm: Chaque DSP que j'ai vu inclut une répétition, une multiplication, une accumulation, mais toutes n'incluent pas de boucles plus généralisées à zéro overhead. En fait, je ne suis pas tout à fait sûr de savoir pourquoi de telles boucles devraient être considérées uniquement comme une fonctionnalité "DSP", car elles seraient également utiles dans de nombreux codes de "processeurs classiques".
Supercat
3

Les premiers processeurs Intel présentaient les fonctionnalités suivantes, dont beaucoup sont désormais obsolètes en mode 64 bits:

  • Instructions ENTER, LEAVE et RET nn [les premiers manuels expliquaient explicitement ceux qui ont été introduits pour les langages structurés en blocs, par exemple Pascal, qui prend en charge les procédures imbriquées]
  • des instructions pour accélérer l’arithmétique des BCD (AAA, AAM, etc.); également support BCD en x87
  • Instructions JCXZ et LOOP pour la mise en oeuvre de boucles comptées
  • INTO, pour générer un piège sur un dépassement arithmétique (par exemple, dans Ada)
  • XLAT pour les recherches de table
  • BOUND pour vérifier les limites du tableau

L’indicateur de signature, situé dans le registre d’état de nombreuses CPU, permet de réaliser facilement des opérations arithmétiques signées ET non signées.

Le jeu d'instructions SSE 4.1 introduit des instructions pour le traitement des chaînes, comptées et terminées à zéro (PCMPESTR, etc.)

De plus, j'imagine qu'un certain nombre de fonctionnalités au niveau du système ont été conçues pour assurer la sécurité du code compilé (vérification de la limite de segment, portes d'appel avec copie de paramètres, etc.).

zvrba
la source
3

Certains processeurs ARM, principalement ceux des périphériques mobiles, incluent (d) l’extension Jazelle, qui est un interpréteur JVM matériel; il interprète directement le bytecode Java. La JVM compatible Jazelle peut utiliser le matériel pour accélérer l'exécution et éliminer une grande partie de la JIT, mais le repli sur la VM logicielle est toujours garanti si le bytecode ne peut pas être interprété sur une puce.

Les processeurs avec cette unité incluent l'instruction BXJ, qui place le processeur en mode "Jazelle" spécial, ou si l'activation de l'unité a échoué, elle est simplement interprétée comme une instruction de branche normale. L'unité réutilise les registres ARM pour maintenir l'état de la JVM.

ThumbEE est le successeur de la technologie Jazelle

usoban
la source
2

Autant que je sache, c'était plus courant dans le passé.

Lors d’ une séance de questions au cours de laquelle James Gosling a déclaré qu’il existait des personnes qui essayaient de créer du matériel pouvant mieux gérer le bytecode de la machine virtuelle Java, mais qu’elles trouveraient alors un moyen de le faire avec des informations "génériques" communes x86 (peut-être en compilant le fichier). bytecode de manière intelligente).

Il a mentionné qu’il était avantageux d’utiliser la puce populaire générique (telle que celle d’Intel), car une grande société consacre d’énormes sommes d’argent au produit.

La vidéo vaut le détour. Il en parle à la minute 19 ou 20.

Pedro Henrique A. Oliveira
la source
2

J'ai fait une recherche rapide de page et il semble que personne n'ait mentionné les processeurs développés spécifiquement pour exécuter Forth . Le langage de programmation Forth est basé sur une pile, compact et utilisé dans les systèmes de contrôle.

Paddy3118
la source
2

Le processeur Intel iAPX a été spécialement conçu pour les langues OO. N'a pas tout à fait travaillé, cependant.

L' iAPX 432 ( architecture Intel Advanced Processor ) était le premier microprocesseur 32 bits d'Intel, introduit en 1981 en tant que jeu de trois circuits intégrés. Il s’agissait de la conception majeure d’Intel pour les années 1980, mettant en œuvre de nombreuses fonctionnalités avancées de gestion multitâche et de gestion de la mémoire. La conception a donc été qualifiée de Micromainframe ...

L'iAPX 432 a été "conçu pour être entièrement programmé dans des langages de haut niveau" , Ada étant le principal logiciel, il prend en charge la programmation orientée objet et la récupération de place directement dans le matériel et le microcode . La prise en charge directe de diverses structures de données visait également à permettre aux systèmes d’exploitation modernes de l’iAPX 432 d’être implémentés avec beaucoup moins de code de programme que pour les processeurs ordinaires. Ces propriétés et caractéristiques ont permis de concevoir un matériel et un microcode beaucoup plus complexes que la plupart des processeurs de l'époque, notamment les microprocesseurs.

En utilisant la technologie des semi-conducteurs de son époque, les ingénieurs d’Intel n’ont pas été en mesure de traduire cette conception en une première mise en œuvre très efficace. Parallèlement au manque d'optimisation d'un compilateur Ada précoce, cela a contribué à la lenteur, mais au coût, des systèmes informatiques performants, réalisant des performances typiques à environ 1/4 de la vitesse de la nouvelle puce 80286 à la même fréquence d'horloge (au début de 1982).

Cet écart de performances initial par rapport à la ligne 8086 plutôt profilée et à bas prix était probablement la principale raison pour laquelle le plan d’Intel visant à remplacer cette dernière (plus tard connu sous le nom de x86) par l’iAPX 432 a échoué. Bien que les ingénieurs aient trouvé des moyens d'améliorer la conception de la prochaine génération, l' architecture iAPX 432 Capability commençait désormais à être considérée davantage comme une surcharge de mise en œuvre que comme un support de simplification à laquelle elle était destinée.

Le projet iAPX 432 était un échec commercial pour Intel ...

juste au passage
la source
En lisant le papier, il semble que de nombreux aspects de la conception pourraient être utiles dans les frameworks orientés objet tels qu'ils sont populaires aujourd'hui. Une architecture combinant id-objet 32 ​​bits et offset 32 ​​bits pourrait, dans de nombreux cas, offrir de meilleures performances de mise en cache que celle où les id d'objet étaient tous de 64 bits (dans la plupart des cas, une application utilisant des milliards d'objets mieux servir en ayant plus, des plus gros: un
disque
1

MOVEM du 68000 était ce qui convenait le mieux pour placer plusieurs registres sur la pile en une seule instruction, ce à quoi de nombreuses langues s'attendaient.

Si vous avez vu MOVEM (MOVE Multiple) précéder JSR (Jump SubRoutine) tout au long du code, vous saviez généralement que vous utilisiez du code C conforme.

MOVEM autorisait l'incrémentation automatique du registre de destination, permettant à chaque utilisateur de continuer l'empilement sur la destination ou la suppression de la pile en cas de décrémentation automatique.

http://68k.hax.com/MOVEM

Myztry
la source
1

L'architecture AVR d'Atmel est entièrement conçue dès le départ pour être adaptée à la programmation en langage C. Par exemple, cette note d'application développe davantage.

OMI ceci est étroitement lié à l’excellente réponse de rockets4kids , avec les premiers PIC16-s en cours de développement pour la programmation directe par assembleur (40 instructions au total), les familles ultérieures ciblant C.

Vorac
la source
1

Lors de la conception du coprocesseur numérique 8087, il était assez courant que les langages effectuent toutes les calculs en virgule flottante en utilisant le type de précision le plus élevé, et arrondissaient le résultat à une précision inférieure lors de l'affectation à une variable de moindre précision. Dans la norme C d'origine, par exemple, la séquence:

float a = 16777216, b = 0.125, c = -16777216;
float d = a+b+c;

favoriserait aet bà double, les ajouter, promouvoir cà double, ajouter, puis stocker le résultat arrondi à float. Même s’il aurait souvent été plus rapide pour un compilateur de générer du code permettant d’exécuter des opérations directement sur le type float, il était plus simple de disposer d’un ensemble de routines à virgule flottante qui ne fonctionneraient que sur le type double, ainsi que de routines à convertir en /. à partir de float, que d'avoir des ensembles distincts de routines pour gérer les opérations sur floatet double. Le 8087 a été conçu autour de cette approche de l'arithmétique, effectuant toutes les opérations arithmétiques en utilisant un type à virgule flottante de 80 bits [80 bits a probablement été choisi pour les raisons suivantes:

  1. Sur de nombreux processeurs 16 et 32 ​​bits, il est plus rapide de travailler avec une mantisse 64 bits et un exposant séparé que de travailler avec une valeur qui divise un octet entre la mantisse et l'exposant.

  2. Il est très difficile d'effectuer des calculs qui soient précis à la précision des types numériques utilisés. si vous essayez par exemple de calculer quelque chose comme log10 (x), il est plus facile et plus rapide de calculer un résultat précis à moins de 100 ul d'un type 80 bits que de calculer un résultat précis à moins de 1ulp d'un 64 bits Si vous arrondissez le premier résultat à une précision de 64 bits, vous obtiendrez une valeur de 64 bits plus précise que la dernière.

Malheureusement, les versions futures du langage ont changé la sémantique du fonctionnement des types à virgule flottante; alors que la sémantique 8087 aurait été très utile si les langages les avaient toujours pris en charge, si les fonctions f1 (), f2 (), etc. renvoyaient le type float, de nombreux auteurs de compilateurs se chargeraient de créer long doubleun alias pour le type double 64 bits plutôt que le type 80 bits du compilateur (et ne fournissent aucun autre moyen de créer des variables 80 bits), et d'évaluer arbitrairement quelque chose comme:

double f = f1()*f2() - f3()*f4();

de l'une des manières suivantes:

double f = (float)(f1()*f2()) - (extended_double)f3()*f4();
double f = (extended_double)f1()*f2() - (float)(f3()*f4());
double f = (float)(f1()*f2()) - (float)(f3()*f4());
double f = (extended_double)f1()*f2() - (extended_double)f3()*f4();

Notez que si f3 et f4 renvoient respectivement les mêmes valeurs que f1 et f2, l'expression d'origine doit clairement renvoyer zéro, mais nombre de ces dernières expressions ne le peuvent pas. Cela a conduit des personnes à condamner la "précision supplémentaire" du 8087 alors même que la dernière formulation serait généralement supérieure à la troisième et que, avec un code utilisant le double type étendu de manière appropriée, il serait rarement inférieur.

Dans les années qui ont suivi, Intel a réagi à la tendance du langage (à mon humble avis) à forcer les résultats intermédiaires à être arrondis à la précision des opérandes en concevant leurs processeurs ultérieurs de manière à favoriser ce comportement, au détriment du code précision sur les calculs intermédiaires.

supercat
la source
Notez que vous avez déjà une réponse ( ci-dessus ) dans ce post. Sont-ils des réponses qui pourraient / devraient être fusionnées en une seule?
@MichaelT: Je ne le pense pas - l'un traite de la conception de la pile et l'autre de la sémantique à virgule flottante.
Supercat
Juste pour être sûr. Personnellement, je pense qu’il serait possible de donner une réponse plus forte (en utilisant des en-têtes pour séparer les sections), mais c’est ce que j’en pense. Vous voudrez peut-être quand même utiliser des en-têtes pour identifier clairement en haut de la page ce que chaque partie de la réponse adresse ( ## How the stack changed the processoret ## How floating point changed the processor) de manière à ce que les gens puissent avoir la bonne mentalité lorsqu’ils le lisent et soient moins enclins à penser que vous avez été distrait dans votre réponse ou votre nouvelle publication. idem (similaire) réponses.
@MichaelT: Les deux réponses sont suffisamment dissociées pour que je pense qu'elles devraient être votées séparément. Bien que le 80486 ait absorbé les fonctions précédemment remplies par le 8087/80287/80387, les 8086 et 8087 ont été conçus en tant que puces séparées avec des architectures presque indépendantes. Bien que les deux aient exécuté du code à partir d’un flux d’instructions commun, cela a été traité en faisant en sorte que le 8086 traite certaines séquences d’octets comme des requêtes pour générer des requêtes de lecture / écriture d’adresses tout en ignorant le bus de données et en ignorant tout ce qui se passait.
Supercat