Trois jeux d’instructions font tourner presque tous les ordinateurs en service. Le x86-64 fait tourner les PC et la plupart des serveurs. L’ARM64 fait tourner les téléphones, les tablettes, les ordinateurs d’Apple et une part croissante des serveurs. Le RISC-V est le nouveau venu : une ISA ouverte que chacun peut implémenter, déjà courante dans les microcontrôleurs et les cœurs embarqués. Le livre de Tanenbaum compare un autre trio, de 2013 : l’IA-32 sur 32 bits, l’ARMv7 32 bits d’une puce de téléphone et l’AVR 8 bits d’un microcontrôleur. Les idées restent valables ; les puces ont évolué.
Ce chapitre met côte à côte les trois ISA actuelles, puis permet de les comparer de la façon qui compte le plus : le même code C, compilé pour chacune.
Trois histoires
Le x86 descend en ligne directe de l’Intel 8086 16 bits de 1978, lui-même marqué par le 8080 8 bits. Le 80386 l’a fait passer à 32 bits en 1985 (IA-32, l’architecture que décrit le livre). L’extension 64 bits, x86-64, est venue d’AMD en 2003 — un cas rare, comme le note le livre, où Intel a dû adopter la conception d’un concurrent. Chaque génération a gardé la précédente en état de marche : c’est la grande force du x86 et l’origine de son héritage encombrant — instructions de longueur variable de 1 à 15 octets, préfixes empilés sur des préfixes, registres aux rôles particuliers, et modes remontant au 8086. Un x86 moderne démarre encore en mode réel 16 bits.
L’ARM est né chez Acorn en 1985, inspiré des recherches RISC de Berkeley : une conception 32 bits à 16 registres, dont le compteur de programme. Le livre qualifie de « récemment publiée » l’ARMv8, aux adresses sur 64 bits. Elle a été annoncée en 2011, et son mode 64 bits, AArch64 (ARM64), s’est révélé une refonte presque complète plutôt qu’une extension : 31 registres généraux, un compteur de programme qui n’est plus un registre général, des instructions pour la plupart plus conditionnelles, et un nouvel encodage fixe sur 32 bits. C’est depuis devenu l’ISA 64 bits la plus répandue, et les conceptions ARM sont sous licence : des entreprises comme Apple ou Qualcomm paient Arm pour l’implémenter.
Le RISC-V a commencé à Berkeley en 2010, comme ISA propre pour la recherche et l’enseignement, et sa base a été ratifiée en 2019. Son trait distinctif n’est pas technique mais juridique : c’est un standard ouvert, libre d’implémentation, sans licence. Il est aussi modulaire : une petite ISA entière de base (RV32I compte environ 40 instructions ; RV64I en ajoute une douzaine pour les mots de 64 bits), plus des extensions standard optionnelles désignées par des lettres — M pour la multiplication et la division, A pour les atomiques, F et D pour la virgule flottante, C pour les instructions compressées de 16 bits, V pour les vecteurs. RV64GC, la cible habituelle des cœurs capables de faire tourner Linux, signifie RV64I plus M, A, F, D (ensemble « G ») et C.
Les conceptions comparées
| x86-64 | ARM64 | RISC-V (RV64GC) | |
|---|---|---|---|
| Philosophie | CISC, compatible jusqu’à 1978 | RISC, pragmatique | RISC, minimal et modulaire |
| Registres généraux | 16 | 31 + registre zéro | 32, x0 toujours à zéro |
| Longueur des instructions | 1 à 15 octets | toujours 4 octets | 4 octets, ou 2 avec l’extension C |
| Arithmétique sur opérandes mémoire | oui (add eax, [rbx]) | non : chargement/rangement | non : chargement/rangement |
| Adressage | base + index × échelle + déplacement | base + décalage, registre mis à l’échelle, pré/post-incrément | base + décalage de 12 bits seulement |
| Indicateurs | oui, positionnés par la plupart des instructions | oui, seulement par les instructions qui le demandent (adds, cmp) | aucun : les branchements comparent des registres |
| Sélection conditionnelle | cmovcc | csel | absente de l’ISA de base (ajoutée par l’extension Zicond de 2023) |
| Adresse de retour | empilée par call | dans le registre de lien x30 | dans ra (x1) |
| Ordre mémoire | TSO | faible | faible (RVWMO) |
| Licence | Intel et AMD | sous licence Arm | ouverte |
Les chapitres précédents ont couvert beaucoup de ces lignes : formats d’instructions, modes d’adressage, ordre mémoire et conventions d’appel.
Le même code, de trois façons
La comparaison ci-dessous compile sept petites fonctions C avec clang en -O2 pour chaque ISA, et montre les vraies instructions et les vrais octets (désassemblés avec llvm-objdump) :
À essayer : Choisissez une fonction ci-dessous pour voir le même code C compilé pour x86-64, ARM64 et RISC-V, avec les octets de chaque instruction.
int get(const int *a, long i) {
return a[i];
}- 8b 04 b7mov eax, dword ptr [rdi + 4*rsi]
- c3ret
- b8617800ldr w0, [x0, x1, lsl #2]
- d65f03c0ret
- 058aslli a1, a1, 0x2
- 952eadd a0, a0, a1
- 4108lw a0, 0x0(a0)
- 8082ret
All seven functions: x86-64 32 instructions, 83 bytes · ARM64 34 instructions, 136 bytes · RISC-V (RV64GC) 35 instructions, 92 bytes
clang -O2 (LLVM 21 for RISC-V), no unrolling or vectorization, position-dependent code; alignment padding removed. → marks a symbol the linker fills in, so its field shows 0 here.
Ce que montrent les sept fonctions :
get— lirea[i]. Le x86 le fait en une instruction de 3 octets grâce à son index mis à l’échelle,[rdi + 4*rsi]; ARM64 aussi en une seule, avec un décalage par registre mis à l’échelle,[x0, x1, lsl #2]. Le seul mode d’adressage de RISC-V est base + constante, il lui faut donc un décalage, une addition puis le chargement : trois instructions au lieu d’une.sum— une boucle. Les trois arrivent à une dizaine d’instructions, dans des styles différents. Le x86 réutilise l’index mis à l’échelle ; ARM64 utilise un chargement post-incrémenté,ldrsw x9, [x0], #4, qui charge et avance le pointeur en une instruction ; RISC-V transforme la boucle pour faire avancer un pointeur jusqu’à une adresse de fin, afin d’utiliserbne, qui compare directement deux registres, sans indicateurs.max— un choix sans branchement sur x86 (cmovg) et ARM64 (csel, sélection conditionnelle). Le RISC-V de base n’a pas de déplacement conditionnel, donc le compilateur émet un branchement.big— une constante de 64 bits. Le x86 a unmovabsde 10 octets qui contient toute la constante. Les instructions ARM64 ne font que 4 octets, donc il construit la constante 16 bits à la fois :movpuis troismovk(move and keep). RISC-V la charge depuis une réserve de constantes en mémoire.bump—counter++sur une globale. Le x86 incrémente directement la mémoire :inc qword ptr [rip + counter], une instruction qui lit, ajoute et écrit. Les ISA chargement/rangement doivent former l’adresse, charger, ajouter et ranger : quatre instructions.call— appeler une autre fonction. Lecalldu x86 empile l’adresse de retour (lepush raxne sert qu’à garder la pile alignée sur 16 octets). Lebld’ARM64 et lejalde RISC-V la placent plutôt dans un registre de lien, plus rapide pour les fonctions feuilles ; commecallfait elle-même un appel, elle doit d’abord sauvegarder son registre de lien sur la pile.divide— l’idivdu x86 a des registres imposés : le dividende doit être dansedx:eax, d’où lemovet lecdqqui étend le signe dansedx. ARM64 et RISC-V divisent deux registres quelconques dans un troisième. (Comme l’a mesuré le chapitre précédent, ils diffèrent aussi sur la division par zéro.)
Taille et nombre d’instructions
Sur les sept fonctions, le x86-64 a besoin de 32 instructions en 83 octets, ARM64 de 34 instructions en 136 octets, et RISC-V de 35 instructions en 92 octets. Sans l’extension C, le même code RISC-V occupe 140 octets : les instructions compressées le réduisent d’environ un tiers, près de la densité du x86 avec un encodage bien plus régulier.
Deux choses ressortent. D’abord, le nombre d’instructions est presque le même. L’écart CISC–RISC est bien plus faible en pratique que ne le veut la légende : le x86 économise une instruction ici ou là grâce aux opérandes mémoire et à son adressage riche, mais les compilateurs l’utilisent surtout comme une machine chargement/rangement. Et à l’intérieur du CPU, un cœur x86 moderne traduit de toute façon ses instructions en micro-opérations de style RISC. Ensuite, les instructions de longueur fixe coûtent de la place mais simplifient le décodage : si chaque instruction fait 4 octets, un cœur peut en décoder huit en parallèle en sachant où commence chacune. Un cœur x86 doit déterminer la longueur de chaque instruction avant de pouvoir décoder la suivante, ce qui explique que les cœurs x86 gardent en cache les micro-opérations déjà décodées.
C’est un petit échantillon de sept fonctions, pas un banc d’essai. Sur des programmes entiers, les trois finissent en général à quelques dizaines de pour cent les uns des autres en taille de code, et les performances dépendent bien plus de la microarchitecture que de l’ISA.
Pourquoi c’est important, et pourquoi ça l’est moins qu’avant
Longtemps, l’ISA a décidé qui pouvait construire une puce : le x86 était de fait limité à Intel et AMD, et la compatibilité avec les binaires existants le maintenait dominant sur les PC. Deux choses ont affaibli cela. La plupart des logiciels sont aujourd’hui compilés depuis leurs sources ou tournent sur une machine virtuelle, donc les porter sur une nouvelle ISA revient à les recompiler — comme l’a montré Apple, deux fois, en faisant passer le Mac de PowerPC à x86 puis de x86 à ARM, avec un traducteur binaire (Rosetta) pour couvrir la transition. Et la microarchitecture compte désormais davantage que l’ISA : un cœur ARM64 bien conçu et un cœur x86-64 bien conçu, gravés avec le même procédé, se tiennent à peu de chose près en performances.
Ce qui diffère encore, c’est qui a le droit d’en construire un. Le x86 est fermé, l’ARM est sous licence, et le RISC-V est ouvert — c’est pourquoi on le voit apparaître partout où des entreprises veulent un processeur sur mesure sans payer quiconque ni lui demander la permission.
À retenir
- Le x86-64 (1978 → AMD64 en 2003) garde une compatibilité totale avec le passé : instructions de longueur variable, 16 registres, opérandes mémoire, indicateurs.
- L’ARM64 (AArch64, 2011) est une refonte 64 bits propre de l’ARM : instructions fixes de 4 octets, 31 registres, un registre de lien, la sélection conditionnelle, sous licence pour les fabricants de puces.
- Le RISC-V (2010, ratifié en 2019) est ouvert et modulaire : une toute petite ISA de base plus des extensions désignées par des lettres (RV64GC) ; pas d’indicateurs, un seul mode d’adressage, des instructions compressées de 16 bits en option.
- Compilées côte à côte, les trois demandent à peu près le même nombre d’instructions (32, 34, 35 ici). Le x86 est le plus dense (83 octets), RISC-V compressé le suit de près (92), ARM64 est le plus gros (136).
- Les différences se voient dans les détails : adressage mis à l’échelle, déplacements conditionnels, constantes de 64 bits, opérandes mémoire, registres de lien, registres de division imposés.
- Aujourd’hui, la microarchitecture compte plus que l’ISA pour les performances ; l’ISA décide surtout qui a le droit de construire la puce.