Récemment, j'ai lu des archives SO et rencontré des déclarations contre l'architecture x86.
Pourquoi avons-nous besoin d'une architecture de processeur différente pour le serveur et le mini / mainframe et le cœur mixte? dit
« architecture PC est un gâchis, tout développeur OS ne vous le dire. »L'apprentissage du langage d'assemblage en vaut-il la peine?( archivé ) dit
" Réalisez que l'architecture x86 est au mieux horrible "Un moyen facile d'apprendre l'assembleur x86? dit
" La plupart des collèges enseignent l'assemblage sur quelque chose comme MIPS parce que c'est beaucoup plus simple à comprendre, l'assemblage x86 est vraiment moche "
et bien d'autres commentaires comme
"Comparé à la plupart des architectures, X86 est plutôt nul."
" Il est définitivement admis que X86 est inférieur à MIPS, SPARC et PowerPC "
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.
Réponses:
Quelques raisons possibles à cela:
IN
etOUT
)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'
MOVSB
instruction a besoin d'un bloc relativement grand de code C pour décrire ce qu'elle fait: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.
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é.
la source
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.
la source
add
après l'autreadd
. 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.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.
la source
J'ai quelques aspects supplémentaires ici:
Considérez l'opération "a = b / c" x86 implémenterait cela comme
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:
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».
la source
there typically won't be a reminder
mais wiki dit que les mips l'ont: en.wikipedia.org/wiki/MIPS_instruction_set#IntegerJe 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:
mov %eax, 0x1c(%esp,%edi,4)
modes d'adressage, et elles ne sont pas décomposées.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.
la source
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.
la source
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.
la source
Outre les raisons que les gens ont déjà mentionnées:
__cdecl
,__stdcall
,__fastcall
, etc.la source
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.
la source
x86 a un ensemble très, très limité de registres à usage général
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
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
À 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.
la source