- vpternlogd d’AVX-512 est une instruction SIMD qui exécute en une seule fois n’importe quelle logique booléenne bit à bit à trois entrées, sélectionnée via une valeur immédiate de 8 bits
- L’idée clé n’est pas de mémoriser des expressions logiques complexes, mais de voir
#imm8 comme une table de correspondance des 8 cas possibles pour les trois entrées A/B/C
- Dès 1985, le blitter de l’Amiga utilisait lui aussi trois sources bitmap et un minterm de 8 bits pour définir de la même manière une combinaison logique ;
0xE2 était souvent utilisé pour les masked sprites
- En lisant les 8 bits de la colonne résultat de bas en haut, on obtient la valeur immédiate ; une condition comme « exactement deux entrées sur trois valent 1 » se construit ainsi directement avec
0x68
- L’exemple de
vpternlogd dans la documentation d’Intel et le fréquent 0xE2 de la demoscene Amiga se rejoignent, montrant qu’une instruction SIMD moderne et un matériel graphique rétro partagent la même logique de conception
vpternlogd dans AVX-512
- vpternlogd est une instruction de logique ternaire bit à bit qui a retenu l’attention dans les documents de présentation de la conception de l’ISA AVX-512
- Elle prend trois entrées A, B et C, et permet d’exprimer n’importe quelle logique booléenne avec une seule instruction
- Exemple :
(NOT A) OR ((NOT B) XOR (C AND A))
- Les entrées peuvent être des registres de 512 bits, ce qui permet d’appliquer une logique complexe simultanément sur l’ensemble des 512 bits
- Au lieu d’ajouter sans cesse des instructions dédiées comme
foo_and_a_or_not_b, on couvre de nombreuses logiques avec une instruction flexible et une valeur immédiate de 8 bits
VPTERNLOGD r0, r1, r3, #imm8
#imm8 détermine quelle fonction logique bit à bit sera exécutée
- Beaucoup de documents se contentent d’expliquer que la valeur immédiate « détermine une certaine fonction binaire », ce qui rend la méthode de calcul concrète peu intuitive
Le blitter de l’Amiga et les minterms
- Dans les années 1980, il était courant que les ordinateurs utilisent des puces personnalisées pour le traitement graphique
- Le blitter du Commodore Amiga 500 appliquait des opérations logiques tout en déplaçant des graphismes bitmap d’un emplacement à un autre
- Il pouvait traiter jusqu’à trois sources bitmap, et l’opération logique entre elles était spécifiée par un minterm de 8 bits
- En ce sens, il partage la même structure que
vpternlogd : trois sources et une valeur de 8 bits pour choisir la combinaison logique
- Beaucoup de programmeurs Amiga réutilisaient des valeurs fréquentes plutôt que de comprendre en détail comment calculer le minterm
0x00 pour effacer un buffer
0xE2 pour dessiner un masked sprite
- Le “Amiga Hardware Reference Manual” de 1989 expliquait le calcul des minterms avec une notation déroutante, ce qui n’aidait pas beaucoup les créateurs de démos de l’époque
Calculer la valeur de 8 bits comme une table de correspondance
#imm8 ou le minterm ne doit pas être vu comme une combinaison d’opérateurs logiques, mais comme une table de correspondance de 8 entrées
- Comme les trois entrées A, B et C valent chacune 0 ou 1, il existe 8 combinaisons possibles
- Il suffit de remplir directement la quatrième colonne avec le résultat souhaité
| A |
B |
C |
Résultat souhaité |
| 0 |
0 |
0 |
? |
| 0 |
0 |
1 |
? |
| 0 |
1 |
0 |
? |
| 0 |
1 |
1 |
? |
| 1 |
0 |
0 |
? |
| 1 |
0 |
1 |
? |
| 1 |
1 |
0 |
? |
| 1 |
1 |
1 |
? |
- Par exemple, si l’on veut produire 1 lorsque exactement deux des trois entrées valent 1, il suffit de remplir la quatrième colonne selon cette condition
- En lisant ensuite les 8 bits de la colonne résultat de bas en haut, on obtient
01101000, soit 0x68
- La fonction
0x68 produit donc 1 lorsque exactement deux des trois entrées valent 1
- On peut obtenir de la même manière la valeur
#imm8 nécessaire pour n’importe quelle fonction logique entre trois sources
Le 0xE2 du masked sprite
- L’une des valeurs de minterm les plus courantes sur Amiga est
0xE2
- Cette valeur est souvent utilisée pour le rendu de sprites 2D masqués
- A : bitmap du sprite
- B : masque du sprite
- C : arrière-plan
- La condition s’exprime simplement avec une logique de programme classique
- si le pixel de masque B est activé, le résultat est le sprite A
- si le pixel de masque B n’est pas activé, le résultat est l’arrière-plan C
| A |
B |
C |
Résultat souhaité |
| 0 |
0 |
0 |
0 |
| 0 |
0 |
1 |
1 |
| 0 |
1 |
0 |
0 |
| 0 |
1 |
1 |
0 |
| 1 |
0 |
0 |
0 |
| 1 |
0 |
1 |
1 |
| 1 |
1 |
0 |
1 |
| 1 |
1 |
1 |
1 |
- En lisant la colonne résultat de bas en haut, on obtient
11100010, soit 0xE2
0xE2 est une valeur de minterm extrêmement fréquente dans la culture demoscene Amiga
Un lien inattendu avec la documentation d’Intel
1 commentaires
Commentaires Hacker News
Il existe une méthode simple pour obtenir la valeur immédiate à partir de l’expression que l’on veut calculer. Par exemple, si l’on veut calculer
(NOT A) OR ((NOT B) XOR (C AND A)), il suffit d’écrire quelque chose comme~_MM_TERNLOG_A | (~_MM_TERNLOG_B ^ (_MM_TERNLOG_C & _MM_TERNLOG_A))C’est littéralement l’expression que l’on veut calculer, et elle est évaluée en valeur immédiate à partir des constantes
_MM_TERNLOG_A/B/Cdéfinies dans les en-têtes d’intrinsics de gcc et clang :typedef enum { _MM_TERNLOG_A = 0xF0, _MM_TERNLOG_B = 0xCC, _MM_TERNLOG_C = 0xAA } _MM_TERNLOG_ENUM;Avec MSVC, il suffit de les définir soi-même
A = 0b11110000,B = 0b11001100,C = 0b10101010Rien qu’en lisant le titre, j’ai cru qu’il signifiait que cette instruction ne fonctionnait pas correctement. En réalité, l’article explique simplement son fonctionnement
Adolescent, je n’ai pas écrit « CRAP! » sur cette page du manuel matériel, mais je l’ai vraiment fixée très longtemps en essayant de comprendre
Au final, comme presque tout le monde, j’ai cherché et utilisé BLTCON0 pour les Bobs et les simples copies, et j’ai fait comme si cette partie n’existait pas
Cela dit, quelques années plus tard, j’ai eu A+ en logique mathématique à l’université ; ce traumatisme a donc peut-être aidé, au moins un peu
À propos du titre, « ternary logic » désigne généralement une logique à trois valeurs de vérité. Mais cet article traite d’une instruction de compilation qui gère toutes les portes logiques binaires à trois entrées
ternloget l’intrinsic s’appelle aussiternarylogic, donc même si c’est regrettable, le titre est appropriéEn plus,
bitwisesuffit déjà dans une certaine mesure à la distinguer de la « logique à trois valeurs », etternaryest très souvent utilisé pour signifier trois entrées.a ? b : cest aussi couramment appelé opérateur ternaire, etternlogpeut effectivement imiter cette opération ternaire ; l’article traite justement de celatrinaryqu’àternary?Du point de vue de C++, JavaScript ou Python, l’usage le plus courant me semble être l’expression ternaire de la forme
(a < b) ? 5 : 2. https://www.programiz.com/cpp-programming/ternary-operatorQuoi qu’il en soit, l’hypothèse de départ n’a pas grande importance. Les mots et expressions ont souvent plusieurs sens, et
ternarysignifie composé de trois parties, ce qui convient ici aussiternaryne veut pas dire celaEn C,
+prend deux entrées, c’est donc un opérateur binaire, tandis que?:prend trois entrées, c’est donc un opérateur ternaire. Comme c’est le seul en C, on l’appelle généralement « the ternary operator », mais il n’a rien de spécialement particulier par naturevpternlogdimplémente tous les opérateurs ternaires bit à bit à trois entréesJe me demande si c’est similaire à la fonction
BitBltde Windows. Elle existe, il me semble, au moins depuis Windows 3.1, et le paramètreopdétermine comment combiner source, destination et masqueJe me souviens de noms de codes comme
BLACKNESS, qui produit du noir indépendamment des entrées, ouCOPY, qui copie la source vers la destination.BLACKNESSetWHITENESSavaient une résonance étrangement poétiqueD’après mon souvenir de Petzold, c’était implémenté en logiciel, mais lors de l’appel l’opcode était transformé en assembleur personnalisé à l’intérieur de la fonction ; c’était donc apparemment un rare cas de code automodifiant dans le système d’exploitation Windows
BitBltutilisait à l’origine des « operation codes » 16 bits complexes qui stockaient l’opération binaire en notation polonaise inversePlus tard, comme sur l’Amiga, un « operation index » a été ajouté pour mettre les mêmes informations dans un seul octet, ce qui est plus court et plus élégant. Aujourd’hui, chaque raster operation code contient à la fois l’operation index et l’operation code, ce qui rend l’encodage redondant. https://devblogs.microsoft.com/oldnewthing/20180528-00/?p=98...
C’est la même manière dont les FPGA implémentent des fonctions logiques arbitraires sous forme de tables de correspondance
Mais en dehors d’usages spécialisés comme les FPGA ou l’instruction dont parle cet article, on ne fait généralement pas cela. Les registres rapides et la RAM statique sont parfois faits en logique, mais il est plus courant de les réaliser directement avec des transistors plutôt qu’avec des portes
74181fait aussi celaSi vous allez sur https://www.sandpile.org puis, dans la page des opcodes sur 3 octets https://www.sandpile.org/x86/opc_3.htm, recherchez
VPTERNLOG, vous verrez aussi AVX512BITALG2, une variante avec masquage byte/word qu’Intel semble avoir planifiée par le passéLa page renvoie aussi, depuis l’opérande
Ib, à une page de tables de vérité ternaires couvrant les 256 cas possibles : https://www.sandpile.org/x86/ternlog.htmLe choix de la fonction
E2comme exemple dans la documentation s’explique peut-être par le fait que, parmi les fonctions booléennes à trois entrées, c’est quasiment le mux le plus basique et standard : siB, alorsA, sinonCC’est une fonction universelle, donc il n’est pas nécessaire d’être fan d’Amiga pour la choisir. Bien sûr, il se peut qu’ils l’aient vraiment été
Autre exemple d’opérations bit à bit encodées dans un entier : les codes ROP du GDI Win32 : https://learn.microsoft.com/en-us/windows/win32/gdi/ternary-...
Il n’y avait pas de manuel matériel Amiga officiel ; à la place, j’ai lu un livre intitulé « Mapping the Amiga ». Il expliquait la même chose de manière un peu plus verbeuse
Je ne me souviens plus quels minterms j’avais utilisés à l’époque, mais je crois qu’avec ce livre j’avais fini par implémenter tant bien que mal des shadebobs, des bobs et du tracé de lignes 3D en XOR
La page correspondante de Mapping the Amiga : https://archive.org/details/1993-thomson-randy-rhett-anderso...