Pourquoi le x86 est-il moche? Pourquoi est-il considéré comme inférieur par rapport aux autres? [fermé]


105

Récemment, j'ai lu des archives SO et rencontré des déclarations contre l'architecture x86.

et bien d'autres commentaires comme

J'ai essayé de chercher mais je n'ai trouvé aucune raison. Je ne trouve probablement pas x86 mauvais parce que c'est la seule architecture que je connaisse.

Quelqu'un peut-il gentiment me donner des raisons de considérer x86 comme laid / mauvais / inférieur par rapport aux autres.


1
Je vais avec S&A sur la base des réponses jusqu'à présent, mais je noterai au passage que CISC n'est pas un problème pour le jeu d'instructions m68k. x86 est ce qu'il est, et vous pouvez le conserver.
dmckee --- ex-moderator chaton

qu'est-ce que "S&A"? "CISC n'est pas un problème pour le jeu d'instructions m68k." -- Pourquoi pas?
griffes

5
Les puces de la série motorala 68000 ont une architecture hautement CISC, mais elles ont un jeu d'instructions uniforme, assez orthogonal et très simple. Pourquoi la différence avec x86? Je ne sais pas. Mais notez qu'il y a une grande différence entre la complexité de la puce et la complexité du jeu d'instructions (c'est-à-dire dans l'interface que voit un programmeur d'assemblage).
dmckee --- ex-moderator chaton

4
+1 pour une question très intéressante.
Turing a terminé le

1
Une étude récente sur l'efficacité énergétique de différents processeurs trouvée ici, avec une bonne discussion sur ce qui a motivé les conceptions du CISC et du RISC. extremetech.com/extreme/…

Réponses:


93

Quelques raisons possibles à cela:

  1. x86 est un ISA relativement ancien (ses ancêtres étaient des 8086, après tout)
  2. x86 a considérablement évolué à plusieurs reprises, mais le matériel est nécessaire pour maintenir la compatibilité descendante avec les anciens binaires. Par exemple, le matériel x86 moderne contient toujours la prise en charge de l'exécution de code 16 bits en mode natif. En outre, plusieurs modèles d'adressage de mémoire existent pour permettre à un code plus ancien d'interagir sur le même processeur, comme le mode réel, le mode protégé, le mode virtuel 8086 et le mode long (amd64). Cela peut être déroutant pour certains.
  3. x86 est une machine CISC. Pendant longtemps, cela signifiait qu'il était plus lent que les machines RISC comme MIPS ou ARM, car les instructions ont une interdépendance des données et des indicateurs rendant la plupart des formes de parallélisme de niveau d'instruction difficiles à implémenter. Les implémentations modernes traduisent les instructions x86 en instructions de type RISC appelées « micro-opérations » sous les couvertures pour rendre ces types d'optimisations pratiques à implémenter dans le matériel.
  4. À certains égards, le x86 n'est pas inférieur, c'est juste différent. Par exemple, les entrées / sorties sont gérées comme un mappage mémoire sur la grande majorité des architectures, mais pas sur le x86. (NB: les machines x86 modernes ont généralement une forme de prise en charge DMA et communiquent avec d'autres matériels via le mappage de la mémoire; mais l' ISA a toujours des instructions d'E / S telles que INet OUT)
  5. L' ISA x86 a très peu de registres architecturaux, ce qui peut forcer les programmes à aller-retour dans la mémoire plus fréquemment que ce qui serait autrement nécessaire. Les instructions supplémentaires nécessaires pour ce faire nécessitent des ressources d'exécution qui pourraient être consacrées à un travail utile, bien qu'un transfert de stockage efficacemaintient la latence faible. Les implémentations modernes avec le renommage des registres sur un grand fichier de registre physique peuvent garder de nombreuses instructions en vol, mais le manque de registres architecturaux était toujours une faiblesse importante pour le x86 32 bits. L'augmentation de x86-64 de 8 à 16 registres entiers et vectoriels est l'un des plus grands facteurs du code 64 bits étant plus rapide que 32 bits (avec l'ABI d'appel de registre plus efficace), et non l'augmentation de la largeur de chaque registre. Une augmentation supplémentaire de 16 à 32 registres d'entiers aiderait certains, mais pas autant. (AVX512 passe à 32 registres vectoriels, cependant, car le code à virgule flottante a une latence plus élevée et a souvent besoin de plus de constantes.) ( Voir commentaire )
  6. Le code d'assemblage x86 est compliqué car x86 est une architecture compliquée avec de nombreuses fonctionnalités. Une liste d'instructions pour une machine MIPS typique tient sur un morceau de papier de format lettre unique. La liste équivalente pour x86 remplit plusieurs pages, et les instructions font juste plus, donc vous avez souvent besoin d'une plus grande explication de ce qu'elles font qu'une liste peut fournir. Par exemple, l' MOVSBinstruction a besoin d'un bloc relativement grand de code C pour décrire ce qu'elle fait:

    if (DF==0) 
      *(byte*)DI++ = *(byte*)SI++; 
    else 
      *(byte*)DI-- = *(byte*)SI--;
    

    Il s'agit d'une seule instruction effectuant un chargement, un stockage et deux ajouts ou soustraits (contrôlés par une entrée d'indicateur), chacun d'eux étant des instructions distinctes sur une machine RISC.

    Bien que la simplicité de MIPS (et des architectures similaires) ne les rend pas nécessairement supérieurs, pour enseigner une introduction à la classe d'assembleur, il est logique de commencer par un ISA plus simple . Certaines classes d'assemblage enseignent un sous-ensemble ultra-simplifié de x86 appelé y86 , qui est simplifié au-delà du point de ne pas être utile pour une utilisation réelle (par exemple, pas d'instructions de décalage), ou certains enseignent uniquement les instructions de base x86.

  7. Le x86 utilise des opcodes de longueur variable, qui ajoutent de la complexité matérielle en ce qui concerne l'analyse des instructions. À l'ère moderne, ce coût devient extrêmement faible car les processeurs deviennent de plus en plus limités par la bande passante mémoire que par le calcul brut, mais de nombreux articles et attitudes "x86 bashing" proviennent d'une époque où ce coût était comparativement beaucoup plus élevé.
    Mise à jour 2016: Anandtech a publié une discussion concernant les tailles d'opcode sous x64 et AArch64 .

EDIT: Ce n'est pas censé être une bash le x86! fête. Je n'avais guère d'autre choix que de faire un peu de dénigrement étant donné la façon dont la question était formulée. Mais à l'exception de (1), toutes ces choses ont été faites pour de bonnes raisons (voir commentaires). Les concepteurs d'Intel ne sont pas stupides - ils voulaient réaliser certaines choses avec leur architecture, et ce sont certaines des taxes qu'ils ont dû payer pour faire de ces choses une réalité.


17
C'est un compromis. C'est une force dans la mesure où la taille binaire peut être plus petite, mais c'est une faiblesse dans la mesure où vous avez besoin d'un matériel très compliqué pour implémenter un analyseur pour ces instructions. La grande majorité des instructions ont de toute façon la même taille - la plupart des raisons pour les opcodes de longueur variable sur x86 sont quand ils ont décidé d'ajouter des fonctionnalités et ont constaté qu'ils ne pouvaient pas représenter ce qu'ils voulaient dans le nombre de bits avec lesquels ils devaient travailler . La grande majorité des gens ne se préoccupent pas autant de la taille binaire que de la complexité du matériel ou de la consommation d'énergie.
Billy ONeal

8
@Joey Adams: Comparez les instructions de longueur variable du x86 avec le mode Thumb d'ARM ( en.wikipedia.org/wiki/ARM_architecture#Thumb ). Le mode pouce entraîne un code objet beaucoup plus petit pour l'ARM, car les instructions plus courtes correspondent directement aux instructions normales. Mais comme il existe un mappage 1: 1 entre les instructions plus grandes et les plus petites, le matériel d'analyse est simple à implémenter. Les instructions de longueur variable du x86 n'ont pas ces avantages car elles n'ont pas été conçues de cette façon au départ.
Billy ONeal

7
(6) Tous les codes opérationnels ne doivent pas être utilisés par tous les programmes, mais bon sang, quand j'ai besoin de SSE3, je suis content de l'avoir.
Chris K

4
@Chris Kaminski: Comment cela n'affecte-t-il pas le matériel? Bien sûr, sur un ordinateur moderne de taille normale, personne ne s'en souciera, mais si je fabrique quelque chose comme un téléphone portable, je me soucie plus de la consommation d'énergie que de presque toute autre chose. Les opcodes de longueur variable n'augmentent pas le temps d'exécution, mais le matériel de décodage nécessite toujours de l'énergie pour fonctionner.
Billy ONeal

5
C'est l'une des choses qui rendent le jeu d'instructions x86 si laid, car il ne peut pas décider s'il s'agit d'un accumulateur ou d'une architecture basée sur un fichier de registre (bien que cela ait été principalement corrigé avec le 386, ce qui a rendu le jeu d'instructions beaucoup plus orthogonal , indépendamment de ce que les 68k fans vous disent).
ninjalj

25

Le principal inconvénient de x86 dans mon esprit est ses origines CISC - le jeu d'instructions contient beaucoup d'interdépendances implicites. Ces interdépendances rendent difficile de faire des choses comme la réorganisation des instructions sur la puce, car les artefacts et la sémantique de ces interdépendances doivent être préservés pour chaque instruction.

Par exemple, la plupart des instructions d'ajout et de soustraction d'entiers x86 modifient le registre des indicateurs. Après avoir effectué un ajout ou une soustraction, l'opération suivante consiste souvent à regarder le registre des indicateurs pour vérifier le dépassement de capacité, le bit de signe, etc. S'il y a un autre ajout après cela, il est très difficile de dire s'il est sûr de commencer l'exécution du deuxième ajout avant que le résultat du premier ajout ne soit connu.

Sur une architecture RISC, l'instruction add spécifierait les opérandes d'entrée et le (s) registre (s) de sortie, et tout ce qui concernait l'opération aurait lieu en utilisant uniquement ces registres. Cela rend beaucoup plus facile de découpler les opérations d'ajout qui sont proches les unes des autres car il n'y a pas de registre d'indicateurs bloomin forçant tout à s'aligner et à exécuter un seul fichier.

La puce DEC Alpha AXP, une conception RISC de style MIPS, était douloureusement spartiate dans les instructions disponibles, mais le jeu d'instructions a été conçu pour éviter les dépendances de registre implicites inter-instructions. Il n'y avait pas de registre de pile défini par le matériel. Il n'y avait pas de registre d'indicateurs définis par le matériel. Même le pointeur d'instructions était défini par le système d'exploitation - si vous vouliez revenir vers l'appelant, vous deviez déterminer comment l'appelant allait vous faire savoir à quelle adresse retourner. Cela était généralement défini par la convention d'appel du système d'exploitation. Sur le x86, cependant, il est défini par le matériel de la puce.

Quoi qu'il en soit, sur 3 ou 4 générations de conceptions de puces Alpha AXP, le matériel est passé d'une implémentation littérale du jeu d'instructions spartiate avec 32 registres int et 32 ​​registres flottants à un moteur d'exécution massivement dans le désordre avec 80 registres internes, renommage de registre, le transfert de résultats (où le résultat d'une instruction précédente est transmis à une instruction ultérieure qui dépend de la valeur) et toutes sortes de boosters de performance sauvages et fous. Et avec toutes ces cloches et sifflets, la puce AXP était encore considérablement plus petite que la puce Pentium comparable de l'époque, et l'AXP était beaucoup plus rapide.

Vous ne voyez pas ce genre de rafales de performances améliorer les choses dans l'arbre généalogique x86 en grande partie parce que la complexité du jeu d'instructions x86 rend de nombreux types d'optimisations d'exécution d'un coût prohibitif, voire impossible. Le coup de génie d'Intel a été d'abandonner l'implémentation du jeu d'instructions x86 dans le matériel - toutes les puces x86 modernes sont en fait des cœurs RISC qui, dans une certaine mesure, interprètent les instructions x86, les traduisant en microcode interne qui préserve toute la sémantique du x86 d'origine. instruction, mais permet un peu de ce RISC dans le désordre et d'autres optimisations sur le microcode.

J'ai écrit beaucoup d'assembleur x86 et je peux pleinement apprécier la commodité de ses racines CISC. Mais je n'ai pas pleinement apprécié à quel point x86 était compliqué jusqu'à ce que je passe un certain temps à écrire l'assembleur Alpha AXP. J'ai été époustouflé par la simplicité et l'uniformité d'AXP. Les différences sont énormes et profondes.


6
Je n'écouterai aucun dénigrement du CISC en soi, à moins que vous ne puissiez expliquer m68k.
dmckee --- ex-moderator chaton

2
Je ne connais pas le m68k, donc je ne peux pas le critiquer.
dthorpe le

4
Je ne pense pas que cette réponse soit suffisamment mauvaise pour voter contre, mais je pense que l'argument global «RISC est plus petit et plus rapide que l'ICCA» n'est pas vraiment pertinent à l'ère moderne. Bien sûr, l'AXP aurait pu être beaucoup plus rapide pour le moment, mais le fait est que les RISC modernes et les CISC modernes sont à peu près les mêmes en termes de performances. Comme je l'ai dit dans ma réponse, la légère pénalité de puissance pour le décodage x86 est une raison de ne pas utiliser x86 pour quelque chose comme un téléphone portable, mais c'est un petit argument pour un ordinateur de bureau ou un ordinateur portable de taille normale.
Billy ONeal

4
@Billy: la taille est plus que la taille du code ou la taille de l'instruction. Intel paie tout à fait une pénalité dans la surface de la puce pour implémenter la logique matérielle pour toutes ces instructions spéciales, cœur de microcode RISC sous le capot ou non. La taille de la matrice a un impact direct sur le coût de fabrication, c'est donc toujours une préoccupation valable avec les conceptions de systèmes modernes.
dthorpe

1
@dthorpe: Je ne suis pas d'accord avec la plupart sinon la totalité de ce que vous avez écrit. Depuis le 8086, vous n'avez pas à vous soucier de savoir s'il est sûr d'exécuter un addaprès l'autre add. Les règles sont claires. Il n'est pas non plus nécessaire que vous vous occupiez de la réorganisation des instructions. Depuis le Pentium Pro au milieu des années 90, le processeur le fait pour vous. Ce que vous mentionnez a peut-être été un problème il y a 20 ans, mais je ne vois aucune raison de le tenir contre l'architecture x86 de nos jours.
Nathan Fellman

21

L'architecture x86 date de la conception du microprocesseur 8008 et de ses proches. Ces processeurs ont été conçus à une époque où la mémoire était lente et si vous pouviez le faire sur la puce du processeur, c'était souvent beaucoup plus rapide. Cependant, l'espace de puces CPU était également coûteux. Ces deux raisons expliquent pourquoi il n'y a qu'un petit nombre de registres qui ont tendance à avoir des fins spéciales et un jeu d'instructions compliqué avec toutes sortes de pièges et de limitations.

D'autres processeurs de la même époque (par exemple la famille 6502) ont également des limitations et des bizarreries similaires. Fait intéressant, la série 8008 et la série 6502 étaient conçues comme des contrôleurs intégrés. Même à l'époque, on s'attendait à ce que les contrôleurs embarqués soient programmés dans l'assembleur et à bien des égards s'adressaient au programmeur d'assemblage plutôt qu'au rédacteur du compilateur. (Regardez la puce VAX pour ce qui se passe lorsque vous répondez à l'écriture du compilateur.) Les concepteurs ne s'attendaient pas à ce qu'ils deviennent des plates-formes informatiques à usage général; c'est à cela que servaient des choses comme les prédécesseurs de l'architecture POWER. La révolution de l'ordinateur domestique a bien sûr changé cela.


4
+1 pour la seule réponse ici de quelqu'un qui semble réellement avoir des antécédents historiques sur la question.
Billy ONeal

3
La mémoire a toujours été lente. Elle est peut-être (relativement parlant) plus lente aujourd'hui qu'elle ne l'était lorsque j'ai commencé avec les Z80 et les CP / M en 1982. L'extinction n'est pas la seule voie d'évolution car avec l'extinction cette direction évolutive particulière s'arrête. Je dirais que le x86 s'est bien adapté au cours de ses 28 ans (jusqu'à présent).
Olof Forshell

4
Les vitesses de mémoire ont brièvement atteint la parité avec les processeurs à l'époque du 8086. Le 9900 de Texas Instruments a une conception qui ne fonctionne que parce que cela s'est produit. Mais le processeur a de nouveau pris de l'avance et est resté là. Seulement maintenant, il existe des caches pour aider à gérer cela.
staticsan

3
@Olof Forshell: Il était compatible assembleur en ce sens que le code d'assemblage 8080 pouvait se traduire en code 8086. De ce point de vue, il s'agissait de 8080 plus extensions, un peu comme vous pourriez voir 8080 comme 8008 extensions.
David Thornley

3
@Olof Forshell: Sauf que le 8086 a été conçu pour que cela se produise. C'était une extension des 8080, et la plupart (peut-être toutes) des instructions 8080 mappées un à un, avec une sémantique évidemment similaire. Ce n'est pas le cas de l'architecture IBM 360, quelle que soit la manière dont vous souhaitez la pousser.
David Thornley

13

J'ai quelques aspects supplémentaires ici:

Considérez l'opération "a = b / c" x86 implémenterait cela comme

  mov eax,b
  xor edx,edx
  div dword ptr c
  mov a,eax

Comme bonus supplémentaire de l'instruction div edx contiendra le reste.

Un processeur RISC exigerait d'abord le chargement des adresses de b et c, le chargement de b et c de la mémoire vers les registres, la division et le chargement de l'adresse de a, puis le stockage du résultat. Syntaxe Dst, src:

  mov r5,addr b
  mov r5,[r5]
  mov r6,addr c
  mov r6,[r6]
  div r7,r5,r6
  mov r5,addr a
  mov [r5],r7

Ici, il n'y aura généralement pas de reste.

Si des variables doivent être chargées via des pointeurs, les deux séquences peuvent devenir plus longues bien que ce soit moins une possibilité pour le RISC car il peut avoir un ou plusieurs pointeurs déjà chargés dans un autre registre. x86 a moins de registres, donc la probabilité que le pointeur se trouve dans l'un d'entre eux est plus petite.

Avantages et inconvénients:

Les instructions RISC peuvent être mélangées avec le code environnant pour améliorer la planification des instructions, c'est moins une possibilité avec x86 qui fait plutôt ce travail (plus ou moins bien selon la séquence) à l'intérieur du CPU lui-même. La séquence RISC ci-dessus aura généralement une longueur de 28 octets (7 instructions de 32 bits / 4 octets chacune) sur une architecture 32 bits. Cela entraînera un plus grand fonctionnement de la mémoire hors puce lors de la récupération des instructions (sept extractions). La séquence x86 plus dense contient moins d'instructions et bien que leurs largeurs varient, vous regardez probablement aussi une moyenne de 4 octets / instruction. Même si vous avez des caches d'instructions pour accélérer ces sept récupérations, cela signifie que vous aurez un déficit de trois ailleurs à compenser par rapport au x86.

L'architecture x86 avec moins de registres à sauvegarder / restaurer signifie qu'elle effectuera probablement des commutateurs de thread et gérera les interruptions plus rapidement que RISC. Plus de registres à enregistrer et à restaurer nécessitent plus d'espace de pile RAM temporaire pour effectuer des interruptions et plus d'espace de pile permanent pour stocker les états des threads. Ces aspects devraient faire de x86 un meilleur candidat pour exécuter du RTOS pur.

Sur une note plus personnelle, je trouve qu'il est plus difficile d'écrire l'assemblage RISC que x86. Je résous cela en écrivant la routine RISC en C, en compilant et en modifiant le code généré. C'est plus efficace du point de vue de la production de code et probablement moins efficace du point de vue de l'exécution. Tous ces 32 registres à suivre. Avec x86, c'est l'inverse: 6-8 registres avec des noms «réels» rend le problème plus gérable et instille plus de confiance que le code produit fonctionnera comme prévu.

Laid? C'est dans les yeux du spectateur. Je préfère «différent».


a, b et c dans mes exemples doivent être considérés comme des variables basées sur la mémoire et non comme des valeurs immédiates.
Olof Forshell

... "dword ptr" est utilisé pour spécifier la taille d'une variable dont la taille n'est pas connue si, par exemple, elle est simplement déclarée comme externe ou si vous avez été paresseux.
Olof Forshell

2
Ce n'est pas la première fois que j'entends la suggestion de l'écrire d'abord en C, puis de le distiller dans l'assembleur. Cela aide vraiment
Joe Plante

Au début, tous les transformateurs étaient des RISC. CISC est né comme une stratégie d'atténuation pour les systèmes de mémoire à cœur ferrique qui étaient TRÈS lents, donc CISC, avec moins d'instructions plus puissantes, a mis moins de pression sur le sous-système de mémoire et a fait une meilleure utilisation de la bande passante. De même, les registres étaient à l'origine considérés comme des emplacements de mémoire sur puce, dans le processeur, pour effectuer des accumulations. La dernière fois que j'ai sérieusement évalué une machine RISC, c'était en 1993 - SPARC et HP Prisim. SPARC était horrible dans tous les domaines. Prisim était jusqu'à 20 fois plus rapide qu'un 486 en add / sub / mul mais aspirait aux transcendantaux. Le SCRC est meilleur.

@OlofForshell Vous dites there typically won't be a remindermais wiki dit que les mips l'ont: en.wikipedia.org/wiki/MIPS_instruction_set#Integer
Alex Zhukovskiy

10

Je pense que cette question a une fausse hypothèse. Ce ne sont que des universitaires obsédés par RISC qui qualifient le x86 de laid. En réalité, l'ISA x86 peut effectuer en une seule instruction des opérations qui prendraient 5 à 6 instructions sur les ISA RISC. Les fans de RISC peuvent contrer le fait que les processeurs x86 modernes décomposent ces instructions «complexes» en microops; toutefois:

  1. Dans de nombreux cas, ce n'est que partiellement vrai ou faux du tout. Les instructions "complexes" les plus utiles dans x86 sont des choses comme les mov %eax, 0x1c(%esp,%edi,4)modes d'adressage, et elles ne sont pas décomposées.
  2. Ce qui est souvent plus important sur les machines modernes, ce n'est pas le nombre de cycles passés (car la plupart des tâches ne sont pas liées au processeur) mais l'impact du code sur le cache d'instructions. 5-6 instructions de taille fixe (généralement 32 bits) auront un impact sur le cache beaucoup plus d'une instruction complexe qui dépasse rarement 5 octets.

x86 a vraiment absorbé tous les bons aspects de RISC il y a environ 10-15 ans, et les qualités restantes de RISC (en fait la définition - le jeu d'instructions minimal) sont nuisibles et indésirables.

Outre le coût et la complexité de la fabrication des processeurs et leurs besoins énergétiques, x86 est le meilleur ISA . Quiconque vous dit le contraire laisse l'idéologie ou l'agenda entraver leur raisonnement.

D'un autre côté, si vous ciblez des appareils embarqués où le coût du processeur compte, ou des appareils embarqués / mobiles où la consommation d'énergie est une préoccupation majeure, ARM ou MIPS a probablement plus de sens. Gardez à l'esprit que vous devrez toujours faire face à la taille de RAM et binaire supplémentaire nécessaire pour gérer un code facilement 3 à 4 fois plus grand, et vous ne pourrez pas vous rapprocher des performances. Que cela compte dépend beaucoup de ce que vous allez exécuter dessus.


3
là où la consommation d'énergie est une préoccupation majeure, ARM ou MIPS a probablement plus de sens ... donc, s'il y a au moins un aspect où ARM ou MIPS ont plus de sens, ne fait-il pas de x86 pas nécessairement le meilleur ISA?
Shahbaz

C'est pourquoi j'ai qualifié "les meilleurs" par "mis à part le coût ... et leurs besoins énergétiques".
R .. GitHub STOP HELPING ICE

1
Je pense que la réduction de la vitesse du processeur par Intel et les plus petites tailles de puces ont largement éliminé le différentiel de puissance. Le nouveau processeur double 64 bits Celeron avec caches 64k L1 et 1 Mo L2 est une puce de 7,5 watts. C'est ma machine de rencontre "Starbucks", et la durée de vie de la batterie est ridiculement longue et fera tourner des anneaux autour d'une machine P6. En tant que gars effectuant principalement des calculs en virgule flottante, j'ai abandonné RISC il y a longtemps. Il rampe juste. SPARC en particulier était atrocement glaciaire. Le processeur Intel i860 est l'exemple parfait de la raison pour laquelle RISC est nul. Intel n'y est jamais retourné.

@RocketRoy: 7,5 watts n'est pas vraiment acceptable pour un appareil alimenté 24 heures sur 24, 7 jours sur 7 (et n'effectuant pas de calculs utiles tout le temps) ou fonctionnant sur une batterie de 3,7 V / 2000 mAh.
R .. GitHub STOP AIDER ICE

2
@RocketRoy "Processeur Intel i860. Intel n'y est jamais retourné." Après quelques recherches, l'i860 ressemble beaucoup à Itanium: VLIW, parallélisme d'instructions ordonné par le compilateur ....
Jonathon Reinhart

9

Le langage assembleur x86 n'est pas si mal. C'est quand vous arrivez au code machine que ça commence à devenir vraiment moche. Les encodages d'instructions, les modes d'adressage, etc. sont beaucoup plus compliqués que ceux de la plupart des CPU RISC. Et il y a un plaisir supplémentaire intégré à des fins de compatibilité ascendante - des choses qui ne démarrent que lorsque le processeur est dans un certain état.

Dans les modes 16 bits, par exemple, l'adressage peut sembler carrément bizarre; il existe un mode d'adressage pour [BX+SI], mais pas un pour [AX+BX]. Des choses comme celles-ci ont tendance à compliquer l'utilisation des registres, car vous devez vous assurer que votre valeur est dans un registre que vous pouvez utiliser selon vos besoins.

(Heureusement, le mode 32 bits est beaucoup plus sain (bien qu'il reste parfois un peu étrange lui-même - segmentation par exemple), et le code x86 16 bits est largement inutile en dehors des chargeurs de démarrage et de certains environnements embarqués.)

Il y a aussi les restes des temps anciens, quand Intel essayait de faire du x86 le processeur ultime. Des instructions de quelques octets de long qui exécutaient des tâches que personne ne fait plus, car elles étaient franchement trop lentes ou compliquées. Les instructions ENTER et LOOP , pour deux exemples - notez que le code de frame de pile C est comme "push ebp; mov ebp, esp" et non "enter" pour la plupart des compilateurs.


2
Je crois que le problème «enter» et «push / mov» est survenu parce que sur certains processeurs, «push / mov» est plus rapide. Sur certains processeurs, "enter" est plus rapide. C'est la vie.
Dietrich Epp

4
Quand j'ai été forcé d'utiliser une machine basée sur x86 et que j'ai commencé à y jeter un coup d'œil (ayant des antécédents m68k), j'ai commencé à me sentir frustré par la programmation asm, ... comme si j'avais appris la programmation avec un langage comme C, puis être forcé d'entrer en contact avec asm ... vous "sentez" que vous perdez le pouvoir d'expression, la facilité, la clarté, la "cohérence", "l'intuitionabilité". Je suis sûr que si j'avais commencé la programmation asm avec x86, j'aurais pensé ce n'est pas si mal ... peut-être ... j'ai aussi fait MMIX et MIPS, et leur "asm lang" est bien meilleur que x86 (si c'est le bon PoV pour le Q, mais peut-être que ce n'est pas le cas)
ShinTakezou

Le problème du mode d'adressage a été résolu dans le 80386. Seul le code 16 bits a des modes d'adressage limités, le code 32 bits est bien meilleur. Vous pouvez obtenir les modes d'adressage 32 bits en code 16 bits en utilisant un préfixe spécial et vice versa.
fuz

@FUZxxl: Ouais ... j'aurais probablement dû mentionner que la laideur est principalement limitée au code 16 bits. Fixé (je pense). :)
cHao

L'inélégance perçue vient principalement de l'idée fausse que les registres d'un 8086 sont des registres à usage général; c'est incorrect. Chacun d'eux a un but spécial et si vous ne vous en tenez pas à leurs objectifs, vous allez passer un mauvais moment.
fuz

3

Je ne suis pas un expert, mais il semble que de nombreuses fonctionnalités pour lesquelles les gens ne l'aiment pas peuvent être les raisons pour lesquelles il fonctionne bien. Il y a plusieurs années, avoir des registres (au lieu d'une pile), des cadres de registre, etc. étaient considérés comme des solutions intéressantes pour rendre l'architecture plus simple aux humains. Cependant, de nos jours, ce qui compte, ce sont les performances du cache, et les mots de longueur variable de x86 lui permettent de stocker plus d'instructions dans le cache. Le "décodage d'instructions", que je crois que les adversaires ont souligné une fois a pris la moitié du jeton, n'est plus autant de cette façon.

Je pense que le parallélisme est l'un des facteurs les plus importants de nos jours - du moins pour les algorithmes qui fonctionnent déjà assez vite pour être utilisables. L'expression d'un parallélisme élevé dans le logiciel permet au matériel d'amortir (ou souvent de masquer complètement) les latences de la mémoire. Bien sûr, l'avenir de l'architecture le plus éloigné est probablement dans quelque chose comme l'informatique quantique.

J'ai entendu dire par nVidia que l'une des erreurs d'Intel était de garder les formats binaires proches du matériel. Le PTX de CUDA effectue des calculs rapides d'utilisation des registres (coloration des graphiques), de sorte que nVidia peut utiliser une machine de registre au lieu d'une machine de pile, mais toujours avoir un chemin de mise à niveau qui ne brise pas tous les anciens logiciels.


9
RISC n'a pas été conçu en pensant aux développeurs humains. L'une des idées derrière RISC était de décharger une partie de la complexité de la puce sur celui qui a écrit l'assemblage, idéalement le compilateur. Plus de registres signifient moins d'utilisation de la mémoire et moins de dépendances entre les instructions, permettant des pipelines plus profonds et des performances plus élevées. Notez que x86-64 a deux fois plus de registres généraux que x86, et cela seul est responsable de gains de performances significatifs. Et les instructions sur la plupart des puces x86 sont décodées avant leur mise en cache, pas après (donc la taille n'a pas d'importance ici).
Dietrich Epp

3
@Dietrich Epp: Ce n'est pas tout à fait vrai. Le x86-64 a plus de registres visibles dans l'ISA, mais les implémentations x86 modernes ont généralement un fichier de registre de style RISC qui est mappé aux registres ISA à la demande pour accélérer l'exécution.
Billy ONeal

"J'ai entendu dire par nVidia que l'une des erreurs d'Intel était de garder les formats binaires proches du matériel." - Je n'ai pas compris ça et la partie PTX de CUDA.
griffes

1
@Dietrech Epp: "Et les instructions sur la plupart des puces x86 sont décodées avant d'être mises en cache, pas après" Ce n'est pas vrai. Ils sont mis en cache avant d'être décodés. Je pense que le Pentium 4 avait un cache de trace supplémentaire qui était mis en cache après le décodage, mais cela a été abandonné.
Nathan Fellman

ce n'est pas vrai, les nouveaux processeurs "sandy bridge" utilisent une sorte de cache de trace (comme ça pour le pentium 4, oh ce vieux: D), donc les technologies s'en vont et reviennent ...
Quonux

3

Outre les raisons que les gens ont déjà mentionnées:

  • x86-16 avait un schéma d'adressage mémoire plutôt étrange qui permettait à un seul emplacement de mémoire d'être adressé jusqu'à 4096 manières différentes, limité la RAM à 1 Mo et obligeait les programmeurs à gérer deux tailles différentes de pointeurs. Heureusement, le passage au 32 bits a rendu cette fonctionnalité inutile, mais les puces x86 portent toujours la cruauté des registres de segment.
  • Sans une faute de x86 en tant que tel , x86 conventions d' appel ne sont pas standardisés comme MIPS était (surtout parce que MS-DOS ne sont pas venus avec des compilateurs), nous laissant avec le désordre de __cdecl, __stdcall, __fastcall, etc.

Hmm ... quand je pense aux concurrents x86, je ne pense pas à MIPS. ARM ou PowerPC peut-être ....
Billy ONeal

@Billy: x86 existe depuis presque toujours. À une époque, MIPS était un concurrent x86. Si je me souviens bien, x86 avait du pain sur la planche pour atteindre un niveau où il était compétitif avec MIPS. (À l'époque où MIPS et SPARC se disputaient dans l'arène des postes de travail.)
Shannon Severance

@Shannon Severance: Ce n'est pas parce que quelque chose était autrefois que ça ne veut pas dire quelque chose qui est.
Billy ONeal

2
@supercat: ce que les gens à l'ère du modèle de mémoire plate x86-32 ont tendance à oublier, c'est que 16 bits signifie 64k de mémoire (quiconque prend la peine de faire le calcul comprendra que la magie n'est pas possible, que le 8086 n'était pas un méchante punition pour les programmeurs sans méfiance). Il y a peu de moyens de contourner 64k mais la solution 8086 était un bon compromis.
Olof Forshell

2
@OlofForshell: Je pense que beaucoup de gens ont déploré le fait que le 8086 n'était pas aussi beau que le 68000 (qui avait un espace d'adressage linéaire de 16 Mo et un chemin clair vers 4 concerts). Certes, passer à un processeur 32 bits facilitera l'accès à plus de 64K, mais le 8086 est une architecture 16 bits qui a été conçue pour être une avancée par rapport au 8080 8 bits. Je ne vois aucune raison pour laquelle Intel aurait dû sauter directement d'un 8 bits à un 32 bits.
supercat

3

Je pense que vous obtiendrez une partie de la réponse si jamais vous essayez d'écrire un compilateur qui cible x86, ou si vous écrivez un émulateur de machine x86, ou même si vous essayez d'implémenter l'ISA dans une conception matérielle.

Bien que je comprenne le "x86 est moche!" arguments, je pense toujours que c'est plus amusant d' écrire un assemblage x86 que MIPS (par exemple) - ce dernier est tout simplement fastidieux. C'était toujours censé être agréable pour les compilateurs plutôt que pour les humains. Je ne suis pas sûr qu'une puce pourrait être plus hostile aux auteurs de compilateurs si elle essayait ...

La partie la plus laide pour moi est la façon dont la segmentation (en mode réel) fonctionne - que toute adresse physique a 4096 segments: alias de décalage. Quand avez-vous eu besoin de ça pour la dernière fois? Les choses auraient été tellement plus simples si la partie segment était strictement des bits d'ordre supérieur d'une adresse 32 bits.


m68k est beaucoup plus drôle et bien plus agréable pour les humains que x86 (ce qui ne peut pas sembler si "humain" à de nombreux programmeurs m68k), si le bon PoV est la façon dont l'humain peut écrire du code dans ces assemblages.
ShinTakezou

Le segment: l'adressage offset était une tentative de rester compatible dans une certaine mesure avec le monde CP / M. Une des pires décisions jamais prises.
Turing a terminé le

@Turing Complete: segment: offset n'était PAS avant tout une tentative de rester compatible avec le monde CP / M. Il s'agissait d'une tentative très réussie pour permettre à un processeur 16 bits d'adresser plus de 64 Ko en plaçant le code, les données, la pile et d'autres zones de mémoire dans différents segments.
Olof Forshell le

1
En réalité, placer les données et la pile dans différents segments était totalement inutile pour C; il n'était utilisable que pour asm. En C, un pointeur peut pointer vers des données avec une durée de stockage statique, automatique ou allouée dynamiquement, il n'y a donc aucun moyen d'élider le segment. Peut-être que c'était utile pour Pascal ou Fortran ou quelque chose comme ça, mais pas pour C, qui était déjà la langue dominante à l'époque ...
R .. GitHub STOP HELPING ICE

2
@Bernd: La raison pour laquelle fs / gs a été choisi pour le stockage local des threads n'est pas que les registres de segment sont bons pour cela. C'est juste que x86 est sérieusement affamé de registres et que les registres de segments étaient inutilisés. Un registre à usage général pointant vers la structure des threads aurait tout aussi bien fonctionné, et en fait de nombreux systèmes RISC avec plus de registres en utilisent un comme pointeur de thread.
R .. GitHub STOP AIDER ICE

1
  1. x86 a un ensemble très, très limité de registres à usage général

  2. il favorise un style de développement très inefficace au niveau le plus bas (l'enfer CISC) au lieu d'une méthodologie efficace de chargement / stockage

  3. Intel a pris la décision horrible d'introduire le segment / offset - modèle d'adressage mémoire pour rester compatible avec (à ce moment déjà!) Une technologie obsolète

  4. À une époque où tout le monde passait au 32 bits, le x86 a freiné le monde des PC grand public en étant un maigre 16 bits (la plupart d'entre eux - le 8088 - même uniquement avec des chemins de données externes 8 bits, ce qui est encore plus effrayant!)


Pour moi (et je suis un vétéran du DOS qui a vu chaque génération de PC du point de vue des développeurs!), Le point 3. était le pire.

Imaginez la situation suivante que nous avions au début des années 90 (grand public!):

a) Un système d'exploitation qui avait des limitations insensées pour des raisons héritées (640 Ko de RAM facilement accessible) - DOS

b) Une extension de système d'exploitation (Windows) qui pourrait faire plus en termes de RAM, mais qui était limitée en ce qui concerne des trucs comme des jeux, etc. et n'était pas la chose la plus stable sur Terre (heureusement cela a changé plus tard, mais je je parle du début des années 90 ici)

c) La plupart des logiciels étaient encore sous DOS et nous devions souvent créer des disquettes de démarrage pour des logiciels spéciaux, car il y avait ce EMM386.exe que certains programmes aimaient, d'autres détestaient (en particulier les joueurs - et j'étais un joueur AVID à cette époque - je sais ce que je je parle ici)

d) Nous étions limités à MCGA 320x200x8 bits (ok, il y en avait un peu plus avec des astuces spéciales, 360x480x8 était possible, mais seulement sans le support de la bibliothèque d'exécution), tout le reste était désordonné et horrible ("VESA" - lol)

e) Mais en termes de matériel, nous avions des machines 32 bits avec pas mal de mégaoctets de RAM et de cartes VGA prenant en charge jusqu'à 1024x768

Raison de cette mauvaise situation?

Une décision de conception simple d'Intel. Compatibilité niveau d'instruction machine (PAS niveau binaire!) Avec quelque chose qui était déjà en train de mourir, je pense que c'était le 8085. Les autres problèmes apparemment sans rapport (modes graphiques, etc ...) étaient liés pour des raisons techniques et à cause du très étroit architecture d'esprit que la plate-forme x86 a apportée avec elle-même.

Aujourd'hui, la situation est différente, mais demandez à n'importe quel développeur assembleur ou à toute personne qui crée des backends de compilateur pour le x86. Le nombre incroyablement bas de registres à usage général n'est rien d'autre qu'un horrible tueur de performances.


Le seul problème majeur avec l'architecture segmentée 8086 était qu'il n'y avait qu'un seul registre de segment non dédié (ES) et que les langages de programmation n'étaient pas conçus pour fonctionner efficacement avec lui. Le style d'adressage mis à l'échelle qu'il utilise fonctionnerait très bien dans un langage orienté objet qui ne s'attend pas à ce que les objets puissent commencer à des adresses arbitraires (si l'on aligne les objets sur les limites de paragraphe, les références d'objet n'auront besoin que de deux octets plutôt que de quatre). Si l'on compare le code Macintosh ancien au code PC, le 8086 semble en fait plutôt bon comparé à 68000.
supercat

@supercat: en fait, le registre es était dédié à quelque chose, à savoir les instructions de chaîne qui nécessitaient un stockage (movs, stos) ou un scan (cmps et scas). Étant donné l'adressage de 64 Ko de chaque registre de segment, les es ont également fourni le "lien manquant" vers la mémoire autre que le code, les données et la mémoire de pile (cs, ds, ss). Les registres de segments offraient une sorte de schéma de protection de la mémoire en ce sens que vous ne pouviez pas adresser en dehors des blocs de mémoire de 64 Ko des registres. Quelle meilleure solution proposez-vous étant donné que le x86 était une architecture 16 bits et les contraintes de lithographie de l'époque?
Olof Forshell le

@OlofForshell: ES était utilisé pour les instructions de chaîne, mais pouvait être utilisé comme registre non validé pour le code ne les utilisant pas. Un moyen d'atténuer le goulot d'étranglement de seg-reg sans exiger trop d'espace opcode serait d'avoir un préfixe "rseg" qui spécifierait que pour l'instruction au format r / m suivante, le champ "r" sélectionnerait CS / SS / DS / ES / FS / GS / ?? / ?? au lieu de AX / BX / CX / DX / SI / DI / SP / BP, et d'avoir des préfixes pour FS / GS et des instructions pour LFS et LGS (comme LDS et LES). Je ne sais pas comment la micro-architecture du 8086 a été conçue, mais je pense que quelque chose comme ça aurait pu fonctionner.
supercat

@supercat: comme je l'ai écrit, "les registres fournissent également le lien manquant vers la mémoire autre que ..." Fs et gs ne sont arrivés que le 386 si je me souviens bien.
Olof Forshell

1
@OlofForshell: Ils ne l'ont pas fait, ce qui a rendu l'architecture 80286 encore pire que l'architecture 8086 à bien des égards. Mon point était que l'ajout de quelques registres de segment de plus (ou même d'un, d'ailleurs) aurait rendu l'architecture 8086 beaucoup plus utile, et le jeu d'instructions aurait pu être plus propre et plus utile si les registres de segment pouvaient être accessibles un peu comme le autres.
supercat
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.