FR 3118505 A1 20220701 FR 2014301 A 20201231 On expose un procédé de traitement par blocs de deux matrices stockées dans une même mémoire partagée, l’une ([a]) étant stockée par rangées et l’autre ([b]) étant stockée par colonnes, utilisant une pluralité d'éléments de traitement (PE), où chaque élément de traitement (PE0) est connecté à la mémoire partagée par un accès de N (256) bits respectif et à un premier élément de traitement adjacent (PE1) par une liaison point à point de N bits bidirectionnelle. Le procédé comprend les étapes suivantes effectuées en un cycle d’instruction de processeur : recevoir (LV) dans les éléments de traitement (PE0-PE3) des segments respectifs différents de N bits d’une même des deux matrices ([b]) par les accès mémoire respectifs ; et échanger (SEND.PE1, RECV.PE1) avec le premier élément de traitement adjacent (PE1), par la liaison point à point, des segments de N bits d’une première ([a]) des deux matrices qui ont été reçus dans les éléments de traitement adjacents (PE0, PE1) lors d’un cycle d'instruction précédent. Figure pour l’abrégé : Fig. 3B Système de traitement de matrices par plusieurs processeurs simultanément Domaine L’invention est relative à la multiplication de matrices de nombres représentés numériquement, notamment à des processeurs assistés d’accélérateurs matériels spécialisés pour les opérations de matrices. Arrière-plan Les technologies d’intelligence artificielle, notamment l’apprentissage profond, sont particulièrement consommatrices de multiplications de grandes matrices, pouvant avoir plusieurs centaines de rangées et de colonnes. On assiste ainsi à l’émergence d’accélérateurs matériels spécialisés dans les multiplications de matrices. La multiplication de grandes matrices est généralement effectuée par blocs, c'est-à-dire en passant par une décomposition des matrices en sous-matrices de taille adaptée aux ressources de calcul. Les accélérateurs sont ainsi conçus pour calculer efficacement les produits de ces sous-matrices. Les accélérateurs matériels dédiés à la multiplication de matrices sont confrontés à des difficultés liées à l’alimentation des unités de calcul de l’accélérateur avec des données de matrices stockées dans une mémoire partagée, sans provoquer une famine des unités de calcul ou une sous-exploitation de ces unités. Par exemple, le format de stockage des données en mémoire peut être inadapté au format requis par les unités de calcul, de sorte qu’une latence et des tampons de données peuvent être introduits pour réorganiser les données. La demande de brevet US2020/0201642 déposée par Kalray prévoit une architecture de processeur intégrant un coprocesseur fortement couplé, ayant ses propres registres de travail, et un mécanisme particulier de transfert de données entre la mémoire et les registres du coprocesseur. Le processeur est capable, grâce à un jeu d’instructions dédié, d’utiliser la bande passante mémoire de façon optimale tout au long du traitement des deux matrices à multiplier. Des défis se présentent cependant en termes d’optimisation de la bande passante mémoire lorsqu’on veut paralléliser le traitement, c'est-à-dire utiliser plusieurs processeurs en parallèle pour traiter la même multiplication de matrices. Résumé On prévoit de façon générale un procédé de traitement par blocs de deux matrices stockées dans une même mémoire partagée, l’une étant stockée par rangées et l’autre étant stockée par colonnes, utilisant une pluralité d'éléments de traitement, où chaque élément de traitement est connecté à la mémoire partagée par un accès de N bits respectif et à un premier élément de traitement adjacent par une liaison point à point de N bits bidirectionnelle. Le procédé comprend les étapes suivantes effectuées en un cycle d’instruction de processeur : recevoir dans les éléments de traitement des segments respectifs différents de N bits d’une même des deux matrices par les accès mémoire respectifs ; et échanger avec le premier élément de traitement adjacent, par la liaison point à point, des segments de N bits d’une première des deux matrices qui ont été reçus dans les éléments de traitement adjacents lors d’un cycle d'instruction précédent. Selon un mode de réalisation, chaque élément de traitement est connecté à un deuxième élément de traitement adjacent par une liaison point à point de N bits bidirectionnelle respective. Le procédé comprend alors les étapes suivantes effectuées en un cycle d’instruction subséquent : recevoir dans les éléments de traitement des segments respectifs différents de N bits d’une même des deux matrices par les accès mémoire respectifs ; et échanger avec le deuxième élément de traitement adjacent, par la liaison point à point, des segments de N bits de la deuxième des deux matrices qui ont été reçus dans les éléments de traitement adjacents lors d’un cycle d’instruction précédent. Chaque segment de N bits reçu peut contenir M rangées ou colonnes appartenant respectivement à M sous-matrices de N bits, chaque sous-matrice ayant un nombre pair R de rangées ou colonnes, où R est divisible par M. Le procédé comprend alors les étapes suivantes : répéter l’étape de réception ou d’échange R fois et enregistrer R segments reçus résultants dans R tuples de registres de N bits respectifs, d’où il résulte que chacun des R tuples contient M rangées ou colonnes appartenant respectivement à M sous-matrices ; transposer les contenus des R tuples de sorte que chacune des M sous-matrices soit entièrement contenue dans un groupe de R/M tuples ; et exploiter individuellement chaque sous-matrice en utilisant les R/M tuples la contenant comme opérande d’une unité d’exécution. On prévoit également un processeur comprenant une pluralité d'éléments de traitement d’architecture VLIW ; une mémoire partagée connectée à chaque élément de traitement par un accès respectif ; une liaison point à point bidirectionnelle reliant deux éléments de traitement adjacents. Chaque élément de traitement a une unité de gestion d’accès mémoire et deux unités arithmétiques et logiques pouvant exécuter simultanément des instructions respectives contenues dans un paquet d’instructions VLIW. Une première des unités arithmétiques et logiques est configurée pour répondre à une instruction de réception de données en stockant dans un registre local identifié par un paramètre, des données présentées sur un canal entrant de la liaison point à point. Une deuxième des unités arithmétiques et logiques est configurée pour répondre à une instruction d’envoi de données en écrivant dans un canal sortant de la liaison point à point le contenu d’un registre local identifié par un paramètre. Le processeur peut comprendre, pour chaque canal de la liaison point à point, une mémoire tampon de type FIFO, la première unité arithmétique et logique d’un élément de traitement étant configurée pour, en réponse à l’instruction de réception, extraire la donnée courante de la mémoire FIFO du canal entrant ; et la deuxième unité arithmétique et logique d’un élément de traitement étant configurée pour, en réponse à l’instruction d’envoi, empiler le contenu du registre local dans la mémoire FIFO du canal sortant. Description sommaire des dessins Des modes de réalisation seront exposés dans la description suivante, faite à titre non limitatif en relation avec les figures jointes parmi lesquelles : La est un schéma-bloc d’un processeur intégrant un coprocesseur fortement couplé à une unité centrale de traitement ; La est un schéma bloc d’un mode de réalisation d’architecture de processeur permettant de quadrupler la puissance de calcul de produits de sous-matrices ; Les figures 3A à 3C illustrent un cycle complet d’échange de données dans la structure de la ; La illustre les contenus de registres d’un élément de traitement au cours des deux phases de traitement ; La illustre les trois phases des figures 3A à 3C sous forme de cycles d’instructions VLIW exécutées dans un élément de traitement. Description détaillée La est un schéma-bloc d’une architecture de processeur telle que divulguée dans la demande de brevet US2020/0201642 susmentionnée. Elle comprend une unité centrale de traitement (CPU) générique 10 fortement couplée à un coprocesseur 12 intégrant des opérateurs matériels dédiés au calcul de produits de matrices. Par « couplage fort » on entend que le coprocesseur obéit cycle par cycle à des instructions machine qui sont exécutées dans l’unité centrale et qui sont mises en œuvre par des unités d’exécution matérielles 14. Plus spécifiquement, certaines instructions machine du jeu d’instructions du processeur incorporent des commandes dédiées au coprocesseur. Lorsque ces instructions parviennent à une unité d’exécution correspondante 14 de l’unité centrale, l’unité d’exécution configure le fonctionnement du coprocesseur par des lignes de commande CTRL. Le coprocesseur est câblé pour obéir immédiatement aux signaux présentés sur ces lignes de commande. En fait, le coprocesseur est une extension des unités d’exécution 14 de l’unité centrale, obéissant à une extension d’un jeu d’instructions génériques du processeur. Ainsi, hormis l’adaptation des unités d’exécution à la commande du coprocesseur, l’unité centrale 10 peut être d’un type générique, permettant notamment d’exécuter un système d’exploitation ou un programme compilé à partir d’un langage classique de programmation logicielle. Le coprocesseur 12 comprend des unités d’exécution de calcul algébrique 16, intégrant notamment des opérateurs matériels dédiés au calcul de multiplications de matrices. Le coprocesseur intègre en outre son propre jeu de registres de travail 18, indépendant d’un jeu de registres 20 classique de l’unité centrale 10. Les registres 18 et 20 sont reliés à une mémoire partagée 22 par un bus de données D de N bits. Des bus d’adresses et de commande de la mémoire, obéissant à des unités d’exécution classiques de l’unité centrale, ne sont pas représentés. Les registres 18 du coprocesseur ont la même taille N que le bus de données et sont configurés pour obéir à des commandes d’une unité d’exécution 14 de l’unité centrale. Deux matrices à multiplier [a] et [b] sont initialement stockées dans la mémoire partagée 22. Selon le langage de programmation utilisé, une matrice est stockée par défaut par rangées (format dit « row-major »), à savoir que les éléments d’une même rangée se trouvent à des adresses consécutives, ou par colonnes (format dit « column-major »), à savoir que les éléments d’une même colonne se trouvent à des adresses consécutives. Le langage de programmation C utilise le premier format, tandis que le langage Fortran utilise le deuxième format. Quoiqu’il en soit, des bibliothèques standard d’algèbre linéaire (BLAS) exploitées depuis ces langages de programmation prévoient des paramètres de transposition pour passer une matrice d’un format à un autre selon les besoins des calculs. Pour les besoins de la présente architecture, les deux matrices à multiplier sont stockées selon des formats complémentaires, par exemple la première matrice [a] est stockée par rangées, tandis que la deuxième matrice [b] est stockée par colonnes. La matrice [b] est ainsi stockée sous forme transposée. La illustre le contenu de la mémoire pour une matrice [a] de x+1 rangées et y+1 colonnes et une matrice [b] de y+1 rangées et z+1 colonnes. La matrice [b], ayant un nombre de rangées égal au nombre de colonnes de la matrice [a], est multipliable par la matrice [a]. Dans la matrice résultat [c] qui comporte x+1 rangées et z+1 colonnes, chacun des éléments c[i, j] est le produit scalaire de la rangée de rang i de la matrice [a] par la colonne de rang j de la matrice [b], où les rangées et les colonnes sont considérées comme des vecteurs de y+1 composantes, à savoir : c[i, j] = a[i, 0..y] • b[0..y, j] Le coprocesseur 12 est conçu pour multiplier, de manière entièrement câblée, deux sous-matrices des matrices source, la première sous-matrice [A] ayant un nombre fixe R de rangées, et la deuxième sous-matrice [B] ayant un nombre fixe de colonnes Q. La dimension restante P des sous-matrices, que l’on appellera ci-après profondeur, est configurable en fonction du format des éléments des matrices et du budget de surface ou de puissance alloué aux opérateurs matériels. La multiplication de ces sous-matrices produit donc une sous-matrice résultat [C] de R×Q éléments. En supposant pour l’instant R égal à Q, ce nombre ainsi que P déterminent les ressources matérielles nécessaires à effectuer la multiplication. Pour les applications d’intelligence artificielle, la valeur P = 16 offre un compromis intéressant et sera utilisée à titre d’exemple dans la suite. En effet, les calculs d’intelligence artificielle utilisent plutôt des multiplications de matrices à précision mixte, où les éléments des matrices à multiplier tiennent sur 8 ou 16 bits, rarement 32 bits, tandis que les éléments des matrices résultat tiennent sur 32 ou 64 bits, en représentation flottante, fractionnaire ou entière. Les petites précisions des matrices à multiplier réduisent la complexité des opérateurs et autorisent des profondeurs P supérieures à celles requises pour traiter les nombres à virgule flottante « simple précision » et « double précision » classiquement utilisés dans des unités centrales génériques, et respectivement codés sur 32 et 64 bits. Par ailleurs, chaque sous-matrice à multiplier est considérée comme ayant une taille globale multiple de N bits, où N est la taille du bus de données D, que l’on supposera égale à 256 bits à titre d’exemple dans la suite. Cela mène à des cas pratiques où les sous-matrices ont R = 4 rangées ou colonnes d’une profondeur de 64 bits ou un multiple de 64 bits. Cette profondeur est occupée, selon les applications, par des octets ou des mots de 16 à 64 bits. Il peut s’agir d’entiers ou de nombres en virgule fixe ou flottante. Si l’on veut traiter en parallèle plusieurs produits de sous-matrices, il viendrait naturellement à l’idée d’utiliser en parallèle plusieurs processeurs du type de la . Cependant, la puissance de calcul n’est pas systématiquement multipliée par le nombre de processeurs mis en parallèle, car la bande passante mémoire doit également augmenter compte tenu de certaines caractéristiques d’une multiplication de matrices, qui impliquent que chaque processeur est amené à travailler sur des mêmes données que ses voisins. Plus spécifiquement, deux processeurs qui calculent chacun une sous-matrice dans un même groupe de rangées de la matrice résultat utilisent chacun une sous-matrice source également utilisée par l’autre. En d’autres termes, une même sous-matrice est utilisée deux fois, une fois par chaque processeur, ce qui peut impliquer deux lectures de chaque sous-matrice en mémoire. Il en va de même lorsque deux processeurs calculent dans un même groupe de colonnes. Dans le meilleur des cas, la quantité totale de lectures mémoire pour un produit de matrices R×P par P×Q augmente proportionnellement à la racine carrée du nombre de processeurs : R×P + P×Q pour un processeur, 4×(R/2×P + P×Q/2) pour quatre processeurs, 16×(R/4×P + P×Q/4) pour seize processeurs, etc. La est un schéma bloc d’un mode de réalisation d’architecture de processeur permettant de quadrupler la puissance de calcul de produits de sous-matrices tout en quadruplant seulement la bande passante mémoire, alors qu’une réalisation optimisée de manière classique demanderait de multiplier par huit cette bande passante. Le processeur comprend quatre éléments de traitement PE0 à PE3, chacun pouvant avoir la structure du processeur de la . Chaque élément de traitement est relié à la mémoire partagée 22 par un bus de données respectif indépendant D0-D3 de N = 256 bits. La mémoire 22 n’a pas besoin d’avoir une structure à quadruple accès complète, c'est-à-dire où chacun des bus D0 à D3 permet d’accéder à toute la mémoire. En effet, comme on le verra plus loin, aucun élément de traitement n’aura besoin d’accéder en mémoire à des données utilisées par un autre élément de traitement. Ainsi, la mémoire 22 peut être de structure à 4 banques (« multi-bank »), significativement plus simple à réaliser qu’une mémoire à réel quadruple accès. Par ailleurs, les éléments de traitement sont connectés en anneau par l’intermédiaire de liens point à point bidirectionnels de N = 256 bits, à savoir un lien X01 entre les éléments PE0 et PE1, X02 entre les éléments PE0 et PE2, X13 entre les éléments PE1 et PE3, et X23 entre les éléments PE2 et PE3. Chacun des liens point à point est connecté à ses deux éléments de traitement adjacents, plus spécifiquement aux bancs de registres 18 de ces éléments de traitement, de manière qu’un élément de traitement puisse transférer le contenu de l’un quelconque de ses registres 18 vers un registre 18 quelconque d’un des éléments de traitement adjacents. Un tel transfert peut être orchestré par l’exécution dans l’un des éléments de traitement d’une instruction d’envoi notée « SEND.PE $v », où PE désigne l’élément de traitement cible (en fait le lien X à utiliser) et $v le registre local dont le contenu (en pratique un vecteur) est à envoyer. L’élément de traitement cible exécute une instruction de réception complémentaire notée « RECV.PE $v », où PE désigne l’élément de traitement source (en fait le lien X à utiliser) et $v le registre local où les données transférées sont à stocker. Les instructions SEND et RECV peuvent être mises en œuvre de manière similaire à des instructions « PUSH » et « POP » servant classiquement à gérer une mémoire tampon de type FIFO. Chaque canal d’une liaison point à point est alors pourvu d’une mémoire FIFO. Alors, une instruction RECV provoque l’extraction de la donnée courante de la mémoire FIFO du canal entrant, et une instruction SEND provoque l’empilement de la donnée dans la mémoire FIFO du canal sortant. Dans ce cas, en fonction de la taille des mémoires FIFO, les instructions SEND et RECV exécutées sur des éléments de traitement adjacents peuvent être exécutées avec un décalage de plusieurs cycles sans déclencher une attente entre ces éléments de traitement. Si une instruction RECV est exécutée trop tôt (alors que la mémoire FIFO du canal entrant est vide), l’élément de traitement est mis en attente. Si une instruction SEND est exécutée alors que la mémoire FIFO du canal sortant est pleine, l’élément de traitement est aussi mis en attente. Les figures 3A à 3C illustrent un cycle complet d’échange de données dans la structure de la , permettant de traiter 16 segments de rangée de 256 bits de la matrice [a] et 16 segments de colonne de 256 bits de la matrice [b]. Les 256 bits de chaque segment sont regroupés par octets numérotés [0..31]. A la , lors d’une première phase, chacun des éléments de traitement PE0 à PE3 reçoit en parallèle de la mémoire un bloc de quatre segments, respectivement a[0..3, 0..31], a[4..7, 0..31], a[8..11, 0..31], et a[12..15, 0..31]. Chaque segment ayant la taille du bus de données, cette phase prend en fait quatre cycles de lecture mémoire. A la , lors d’une deuxième phase qui peut suivre immédiatement la première phase, chacun des éléments de traitement PE0 à PE3 reçoit en parallèle de la mémoire un bloc de quatre segments, respectivement b[0..31, 0..3], b[0..31, 8..11], b[0..31, 4..7], et b[0..31, 12..15]. Chaque segment ayant la taille du bus de données, cette phase prend aussi quatre cycles de lecture mémoire. Pendant cette deuxième phase, les éléments de traitement adjacents verticalement s’échangent les segments de la matrice [a], reçus à la phase précédente, par leurs liaisons point à point correspondantes. Plus spécifiquement, les éléments de traitement PE0 et PE1 échangent les segments a[0..3, 0..31] et a[4..7, 0..31], et les éléments de traitement PE2 et PE3 échangent les segments a[8..11, 0..31] et a[12..15, 0..31]. Ces échanges de segments, compte tenu de la taille de 256 bits des liaisons point à point, prennent aussi quatre cycles. Ainsi, pendant cette phase ont lieu, dans chaque élément de traitement, quatre cycles de lecture de segments et quatre cycles d’échange de segments. Cependant, comme les cycles de lecture et les cycles d’échange n’ont pas lieu sur les mêmes canaux de communication, les cycles d’échange peuvent avoir lieu en même temps que les cycles de lecture. Cela est rendu possible à l’aide d’une architecture d’élément de traitement pouvant exécuter plusieurs opérations en même temps, notamment une architecture de cœur VLIW (« Very Long Instruction Word »), où les opérations de lecture et les opérations d’échange peuvent être mises en œuvre par deux unités d’exécution indépendantes, chacune répondant en parallèle à une instruction dédiée. Il en résulte que la deuxième phase peut ne prendre que quatre cycles. Dans cette deuxième phase on peut aussi impliquer d’autres unités d’exécution indépendantes, commandées en parallèle par d’autres instructions VLIW, pour effectuer des calculs impliquant les données de matrice présentes dans les éléments de traitement, comme on l’illustrera ultérieurement, de sorte qu’il n’y ait aucun temps mort dans l’occupation des bus mémoire, et sans lire plusieurs fois les mêmes données en mémoire. A la , lors d’une troisième phase qui peut suivre immédiatement la deuxième phase, les éléments de traitement adjacents horizontalement s’échangent les segments de la matrice [b], reçus à la phase précédente, par leurs liaisons point à point correspondantes. Plus spécifiquement, les éléments de traitement PE0 et PE2 échangent les segments b[0..31, 0..3] et b[0..31, 4..7], et les éléments de traitement PE1 et PE3 échangent les segments b[0..31, 8..11] et b[0..31, 12..15]. Ces échanges de segments prennent quatre cycles. En outre, pendant cette troisième phase, on démarre le traitement d’une nouvelle série de 16 segments de la matrice [a] et 16 segments de la matrice [b]. Ainsi, chacun des éléments de traitement PE0 à PE3 reçoit en parallèle de la mémoire un nouveau groupe de quatre segments, respectivement a[0..3, 32..63], a[4..7, 32..63], a[8..11, 32..63], et a[12..15, 32..63]. La illustre les contenus de registres $v (vecteurs) de l’élément de traitement PE0 au cours des deux premières phases susmentionnées. Dans le cadre d’un exemple utilisé par la suite, on suppose que chaque élément de traitement est capable d’effectuer, en un cycle d’instruction, une multiplication de deux sous-matrices [A] et [B] de 4×16 et 16×4 octets (sous-matrices ayant une « profondeur » de 16 octets) enchainée avec une accumulation dans une sous-matrice [C] de 4×4 mots de 32 bits. Lors des quatre premiers cycles de lecture (instructions notées LV – « Load Vector »), les segments successifs a[0, 0..31] à a[3, 0..31] sont enregistrés respectivement dans des registres $v0 à $v3. L’élément de traitement étant prévu pour multiplier des sous-matrices ayant une profondeur de 16 octets, chaque registre contient en fait deux rangées ou vecteurs de 16 octets appartenant à deux sous-matrices adjacentes dans la matrice source [a], notées A0a et A0b. Lors des quatre cycles d’échange subséquents (instructions notées RECV.PE1 pour la réception de l’élément de traitement PE1), les segments successifs a[4, 0..31] à a[7, 0..31] sont enregistrés respectivement dans des registres $v4 à $v7. Il en résulte que chacun de ces registres contient en fait deux vecteurs de 16 octets appartenant à deux autres sous-matrices adjacentes dans la matrice source [a], notées A1a et A1b. Des sous-matrices B0a, B0b et B2a, B2b de la matrice source [b] se trouvent organisées similairement dans des registres $v8 à $v11 et $v12 à $v15. Compte tenu de cette organisation des octets dans les registres, un registre ne convient pas pour servir d’opérande à une unité d’exécution qui attend, pour chaque opérande, des données d’une seule sous-matrice. Afin de retrouver dans chaque registre des données d’une seule sous-matrice, les données des registres $v0 à $v3 et $v4 à $v7 sont transposées en considérant les contenus des registres comme R rangées (ou Q colonnes) consécutives d’une matrice. Une transposition est effectuée, par exemple, par une instruction notée MT44D (« Matrix Transpose 4×4 Double ») qui opère sur une matrice de 4×4 éléments de double précision (64 bits ou 8 octets). Les quatre rangées de la matrice 4×4 en question sont les contenus des quatre registres identifiés dans le paramètre de l’instruction MT44D. Les registres illustrés à la sont découpés par blocs de 64 bits, tels qu’utilisés par les instructions MT44D. La taille de 64 bits des éléments de cette transposition découle de la taille de segment N (256 bits) divisée par R (4). A la suite des transpositions, comme cela est illustré à la , chacune des sous-matrices A0a, A0b, A1a et A1b est entièrement contenue dans une paire respective de registres ($v0, $v1), ($v2, $v3), ($v4, $v5) et ($v6, $v7). L’organisation des octets d’une sous-matrice dans une paire de registres est ainsi telle que chaque registre contienne une sous-matrice de quatre (R = 4) rangées et huit (N/R = 8) octets, ici un octet par colonne, mais cette organisation n’est pas indispensable, car pour toute organisation choisie, les octets sont réordonnés par une structure câblée fixe avant d’être fournis à un opérateur matériel. Ce qui est important pour optimiser le traitement est que chaque registre contienne des données appartenant à une seule sous-matrice. La illustre les trois phases des figures 3A à 3C sous forme de cycles d’instructions VLIW exécutées dans l’élément de traitement PE0. Cinq colonnes correspondent à des unités d’exécution indépendantes de l’élément de traitement PE0, chacune pouvant exécuter en parallèle une instruction respective d’un « paquet » VLIW. Une unité d’exécution LSU (« Load/Store Unit ») gère les accès à la mémoire partagée (instructions LV). Deux unités d’exécution arithmétiques et logiques ALU0, ALU1 sont conçues pour exécuter en parallèle deux instruction de même type, en principe des instructions de calcul. Ici, l’une des unités, ALU0, est conçue en outre pour gérer la réception des données des éléments de traitement adjacents par les liaisons point à point (instructions RECV.PE), et l’autre unité, ALU1, est conçue pour gérer l’envoi de données aux éléments de traitement adjacents par les liaisons point à point (instructions SEND.PE). Une unité d’exécution BCU (« Branch Control Unit ») gère en principe les comparaisons, les branchements et les boucles. Cette unité BCU est complétée pour gérer aussi des mouvements de données dont les transpositions (instructions MT44D). Avec ces extensions des unités d’exécution ALU et BCU, on pourra exécuter en parallèle dans des paquets VLIW un certain nombre d’instructions intervenant dans le traitement des matrices, selon une séquence n’introduisant aucun cycle à vide quant aux accès à la mémoire partagée. Finalement, le coprocesseur est conçu pour exécuter des instructions spécifiques au traitement des matrices, comme, dans le cadre de l’exemple considéré, la multiplication de sous-matrices de 4×16 et 16×4 octets avec accumulation dans une sous-matrice de 4×4 mots de 32 bits, instructions notées MMA4164. De telles sous-matrices ont une taille de 512 bits, à savoir que chacune est contenue dans deux registres $v consécutifs. Un opérateur matériel correspondant est alors câblé pour recevoir les contenus adéquatement réordonnés de deux registres $v pour chaque opérande. La colonne « Cyc. » indique le cycle d’instruction et la colonne « Op. » indique les opérations effectuées sur les sous-matrices. Aux cycles 1 à 4 on exécute dans l’unité d’exécution LSU des instructions de lecture en mémoire de quatre segments de 256 bits de la matrice [a], segments qui sont stockés respectivement dans les registres $v0 à $v3. Au cycle 4, les registres $v0 à $v3 contiennent les sous-matrices A0a et A0b, de façon entrelacée, ce qui est noté par A0ab dans la colonne « Op. ». Aux cycles 5 à 8, plusieurs opérations peuvent avoir lieu en parallèle sur les unités d’exécution LSU, ALU0 et ALU1. Par l’unité LSU, quatre segments de la matrice [b] sont lus en mémoire pour être stockés dans les registres $v8 à $v11, formant les matrices B0a et B0b sous forme entrelacée (B0ab). En supposant que l’élément de traitement PE1 adjacent a stocké les sous-matrices A1a et A1b dans ses registres aux quatre cycles précédents, on peut les recevoir par la liaison point à point correspondante, en exécutant aux cycles 5 à 8 des instructions RECV.PE1 dans l’unité ALU0, et les stocker dans les registres $v4 à $v7, aussi sous forme entrelacée (A1ab). Similairement, les sous-matrices A0a et A0b ayant été reçues, elles peuvent être envoyées à l’élément de traitement adjacent en exécutant quatre instructions SEND.PE1 successives dans l’unité ALU1, en même temps que les instructions RECV.PE1 et LV. Aux cycles 9 à 12 les sous-matrices entrelacées B0ab et B2ab sont échangées avec l’élément de traitement PE2 en exécutant des instructions RECV.PE2 et SEND.PE2 correspondantes, utilisant les registres $v12-$v15 et $v8-$v11. En même temps, on peut recevoir un nouveau couple de sous-matrices 4×16 de la matrice source [a], par exemple a[0..3, 32..63]. Aux cycles 13 à 16, toutes les sous-matrices sur lesquelles on souhaite travailler sont disponibles sous forme entrelacée A0ab, A1ab, B0ab, et B2ab dans les registres $v0 à $v15. Quatre transpositions (MT44D) sont alors exécutées dans l’unité d’exécution BCU pour isoler les sous-matrices A0a, A0b, B0a, B0b, A1a, A1b, B2a, et B2b dans des paires respectives de registres. En même temps, on peut recevoir un nouveau couple de sous-matrices 16×4 de la matrice source [b], par exemple b[32..63, 0..4], et échanger les sous-matrices reçues aux cycles 9 à 12. Les quatre éléments de traitement PE0-PE3 sont ainsi alimentés en données des matrices source [a] et [b] pour parcourir par pas de 32 octets toutes les colonnes d’un même groupe de 16 rangées de la matrice [a] et toutes les rangées d’un même groupe de 16 colonnes de la matrice [b], et passer ensuite à deux groupes différents de 16 rangées et 16 colonnes, jusqu’à ce que toutes les rangées et colonnes des matrices source soient parcourues. Dans l’exemple présenté, les quatre éléments de traitement opèrent ensemble sur un premier pas de 32 octets [0..31] dans les rangées 0 à 15 et les colonnes 0 à 15. Les éléments de traitement sont organisés pour calculer les produits scalaires : c[i, j] = a[i, 0..31] • b[0..31, j], où i et j vont chacun de 0 à 15. L’élément de traitement PE0 est organisé pour effectuer le calcul partiel : c[i0, j0] = a[i0, 0..31] • b[0..31, j0], où i0 et j0 vont chacun de 0 à 7, en utilisant : A0a = a[0..3, 0..15], B0a = b[0..15, 0..3], A0b = a[0..3, 16..31], B0b = b[16..31, 0..3], A1a = a[4..7, 0..15], B2a = b[0..15, 4..7], A1b = a[4..7, 16..31], B2b = b[16..31, 4..7]. Pour cela, aux cycles 17 à 24, les sous-matrices de 4×16 et 16×4 qui ont été isolées dans des paires de registres $v sont multipliées avec accumulation (MMA4164) pour calculer leurs contributions de 4×4 mots de 32 bits à la matrice résultat [c], à savoir : c[0..3, 0..3] += A0a*B0a + A0b*B0b, c[0..3, 4..7] += A0a*B2a + A0b*B2b, c[4..7, 0..3] += A1a*B0a + A1b*B0b, c[4..7, 4..7] += A1a*B2a + A1b*B2b. Chaque instruction MMA4164 prend trois paramètres, à savoir un tuple de registres qui reçoit une sous-matrice accumulant le résultat (ici une paire de registres), et les deux paires de registres contenant les sous-matrices opérandes. Selon cette configuration, le résultat du calcul par l’élément de traitement PE0 est une sous-matrice c0[0..7, 0..7] de 8×8 entiers de 32 bits, stockée dans les registres $v40 à $v47. Pendant les mêmes cycles 17 à 24, les unités d’exécution restantes (LSU, ALU0, ALU1, BCU) sont disponibles pour enchaîner sans cycle vide les opérations requises pour préparer les données du pas suivant. Similairement, les éléments PE1 à PE3 sont organisés pour effectuer en parallèle les calculs partiels respectifs : c1[i0, j1] = a[i0, 0..31] • b[0..31, j1] où i0 va de 0 à 7 et j1 de 8 à 15, c2[i1, j0] = a[i1, 0..31] • b[0..31, j0] où i1 va de 8 à 15 et j0 de 0 à 7, et c3[i1, j1] = a[i1, 0..31] • b[0..31, j1] où i1 et j1 vont chacun de 8 à 15. Au cycle 25, chacun des éléments de traitement a calculé, dans ses registres $v40 à $v47, la contribution du pas courant à une sous-matrice individuelle de 8×8 données, formant l’un des quadrants de la sous-matrice résultat c[0..15, 0..15] de 16×16 données en cours de calcul conjoint par les quatre éléments de traitement. Une fois que tous les pas ont été effectués, la sous-matrice résultat c[0..15, 0..15] contenue conjointement dans les registres $v40 à $v47 des quatre éléments de traitement est complète et peut être écrite en mémoire. Le calcul d’une nouvelle sous-matrice résultat disjointe de 16×16 données peut alors être initiée, par exemple c[16..31, 0..15]. L’enchaînement d’instructions de la n’est qu’un exemple permettant d’illustrer clairement les différentes phases. En pratique, chaque instruction peut être exécutée dès que les données qu’elle utilise sont disponibles. Par exemple, une instruction SEND.PE1 peut être exécutée dès que le registre $v concerné contient une valeur à jour. Ainsi, la séquence d’instructions SEND.PE1 illustrée peut commencer dès le cycle 2. Étant donné que les instructions RECV.PE sont censées être quasi synchrones avec les instructions SEND.PE de l’élément de traitement adjacent, la séquence d’instructions RECV.PE peut aussi commencer au cycle 2. Chacune des quatre instructions MT44D est exécutable juste après les instructions respectives SEND.PE1 $v3, RECV.PE1 $v7, SEND.PE1 $v11 et RECV.PE1 $v15. Par ailleurs, dans la séquence illustrée, les données échangées entre éléments de traitement adjacents sont les données non encore transposées, de sorte que ces données sont transposées après l’échange. La transposition pourrait avoir lieu avant l’échange, ou encore de manière combinée aux opérations d’échange. Dans la demande de brevet US2020/0201642, des instructions spécifiques sont prévues, appelées « load-scatter », qui permettent d’effectuer la transposition dès la lecture en mémoire. En utilisant ces instructions à la place des instructions LV, on peut économiser toutes les instructions de transposition MT44D, bien que cela n’affecterait pas la bande passante mémoire, qui est de toute façon occupée à son plein potentiel. Un exemple d’application a été décrit utilisant quatre éléments de traitement connectés en anneau dans le contexte de la multiplication de sous-matrices de 4×16 et 16×4 octets. On peut envisager similairement la multiplication de sous-matrices de 4×8 et 8×4 mots de 16 bits (instruction MMA484), la multiplication de sous-matrices de 4×4 et 4×4 mots de 32 bits (instruction MMA444), ou encore la multiplication de sous-matrices de 4×2 et 2×4 mots de 64 bits (instruction MMA424). Dans tous ces cas, le même schéma de calcul s’applique, la seule adaptation nécessaire se trouvant au niveau de la taille des éléments de la matrice résultat [c]. Ainsi, lorsque celle-ci a des éléments de 64 bits, l’opérande d’accumulation des instructions MMA4 4 est un quadruplet de registres. Le système de traitement de décrit ici peut être interprété comme une parallélisation de la multiplication de matrices s’appuyant sur un dispositif de liaison point à point entre les éléments de traitement selon une topologie d’hypercube (segment pour deux éléments, anneau pour quatre éléments, cube pour huit éléments, deux cubes connectés par les sommets correspondants pour seize éléments, etc.). Cependant les travaux antérieurs sur ce type de parallélisation n’adressent pas la contrainte que les matrices soient stockées dans une mémoire partagée accessible par tous les éléments de traitement, selon une disposition par rangées (« row-major ») ou par colonnes (« column-major »). Le système de traitement décrit ici pour une topologie de liaison en anneau (hypercube de dimension deux) entre quatre éléments de traitement se généralise directement aux systèmes à hypercube de dimension supérieure. Par ailleurs, on a décrit des exemples de réalisation où la largeur du bus mémoire et des liaisons point à point (N = 256 bits) est telle que chaque segment lu ou échangé contient M = 2 rangées appartenant respectivement à deux sous-matrices adjacentes en mémoire. Il en résulte que chaque élément de traitement, après une phase de huit cycles de lecture (LV) et huit cycles d’échange (RECV), reçoit huit sous-matrices qui sont traitées par huit multiplications avec accumulation (MMA4164). Les phases peuvent s’enchaîner sans temps mort quant à l’utilisation de la bande passante mémoire du fait que le nombre de multiplications est au plus égal au nombre de lectures et d’échanges. En doublant la largeur du bus et des liaisons point à point (N = 512), ou en divisant par deux la profondeur des sous-matrices à traiter (4×8, 8×4) par l’opérateur MMA, chaque segment lu ou échangé contient M = 4 rangées appartenant respectivement à quatre sous-matrices adjacentes en mémoire. Il en résulte que chaque élément de traitement, après une phase de huit cycles de lecture (LV) et huit cycles d’échange (RECV), reçoit seize sous-matrices qui seraient traitables par seize multiplications avec accumulation. Dans ce cas, les phases s’enchaîneraient avec un temps mort de huit cycles quant à l’utilisation de la bande passante mémoire du fait que le nombre de multiplications est le double du nombre de lectures et d’échanges. L’intérêt de cette disposition est la réduction des besoins de bande passante de lecture depuis la mémoire partagée, qui peut alors simultanément être utilisée par un autre maître de bus tel qu’une unité DMA. Pour obtenir un enchaînement sans temps mort, on peut configurer les opérateurs MMA pour traiter des matrices opérandes deux fois plus profondes, où chaque matrice opérande reçoit une juxtaposition de deux sous-matrices. Ainsi, pour N = 512, l’opérateur MMA est configuré pour traiter des matrices opérandes 4×32 et 32×4, chacune recevant deux sous-matrices 4×16 ou 16×4. Une alternative adaptée aux cas où il n’est pas faisable d’augmenter la profondeur P, comme en arithmétique flottante 32 ou 64 bits, est d’autoriser dans ce cas l’activation de deux opérations MMA4164 dans chaque paquet d’instructions d’un élément de traitement. Les transpositions (MT) seraient configurées pour opérer sur des blocs de taille adaptée (128 bits pour N = 512). Cette structure est généralisable à tout entier M puissance de 2. Procédé de traitement par blocs de deux matrices stockées dans une même mémoire partagée, l’une ([a]) étant stockée par rangées et l’autre ([b]) étant stockée par colonnes, utilisant une pluralité d'éléments de traitement (PE), où chaque élément de traitement (PE0) est connecté à la mémoire partagée par un accès de N (256) bits respectif et à un premier élément de traitement adjacent (PE1) par une liaison point à point de N bits bidirectionnelle, le procédé comprenant les étapes suivantes effectuées en un cycle d’instruction de processeur : recevoir (LV) dans les éléments de traitement (PE0-PE3) des segments respectifs différents de N bits d’une même des deux matrices ([b]) par les accès mémoire respectifs ; et échanger (SEND.PE1, RECV.PE1) avec le premier élément de traitement adjacent (PE1), par la liaison point à point, des segments de N bits d’une première ([a]) des deux matrices qui ont été reçus dans les éléments de traitement adjacents (PE0, PE1) lors d’un cycle d'instruction précédent. Procédé selon la revendication 1, dans lequel chaque élément de traitement (PE0) est connecté à un deuxième élément de traitement adjacent (PE2) par une liaison point à point de N bits bidirectionnelle respective, le procédé comprenant les étapes suivantes effectuées en un cycle d’instruction subséquent : recevoir (LV) dans les éléments de traitement (PE0-PE3) des segments respectifs différents de N bits d’une même des deux matrices ([a]) par les accès mémoire respectifs ; et échanger (SEND.PE2, RECV.PE2) avec le deuxième élément de traitement adjacent (PE2), par la liaison point à point, des segments de N bits de la deuxième ([b]) des deux matrices qui ont été reçus dans les éléments de traitement adjacents (PE0, PE2) lors d’un cycle d’instruction précédent. Procédé selon la revendication 1, dans lequel chaque segment de N bits reçu contient M rangées ou colonnes appartenant respectivement à M sous-matrices de N bits, chaque sous-matrice ayant un nombre pair R (4) de rangées ou colonnes, où R est divisible par M, le procédé comprenant les étapes suivantes : répéter l’étape de réception ou d’échange R fois et enregistrer R segments reçus résultants dans R tuples de registres de N bits respectifs ($v0-$v3), d’où il résulte que chacun des R tuples contient M rangées ou colonnes appartenant respectivement à M sous-matrices (A0a, A0b) ; transposer les contenus des R tuples de sorte que chacune des M sous-matrices soit entièrement contenue dans un groupe de R/M tuples ($v0-$v1, $v2- $v3) ; et exploiter individuellement chaque sous-matrice en utilisant les R/M tuples la contenant comme opérande d’une unité d’exécution. Processeur comprenant : une pluralité d'éléments de traitement (PE) d’architecture VLIW ; une mémoire partagée (22) connectée à chaque élément de traitement par un accès respectif (D0-D3) ; une liaison point à point bidirectionnelle (X01) reliant deux éléments de traitement adjacents (PE0, PE1) ; chaque élément de traitement ayant une unité de gestion d’accès mémoire (LSU) et deux unités arithmétiques et logiques (ALU0, ALU1) pouvant exécuter simultanément des instructions respectives contenues dans un paquet d’instructions VLIW, où une première des unités arithmétiques et logiques (ALU0) est configurée pour répondre à une instruction de réception de données (RECV.PE1) en stockant dans un registre local ($v4) identifié par un paramètre, des données présentées sur un canal entrant de la liaison point à point ; une deuxième des unités arithmétiques et logiques (ALU1) est configurée pour répondre à une instruction d’envoi de données (SEND.PE1) en écrivant dans un canal sortant de la liaison point à point le contenu d’un registre local ($v0) identifié par un paramètre. Processeur selon la revendication 4, comprenant pour chaque canal de la liaison point à point une mémoire tampon de type FIFO, la première unité arithmétique et logique d’un élément de traitement étant configurée pour, en réponse à l’instruction de réception, extraire la donnée courante de la mémoire FIFO du canal entrant, et la deuxième unité arithmétique et logique d’un élément de traitement étant configurée pour, en réponse à l’instruction d’envoi, empiler le contenu du registre local dans la mémoire FIFO du canal sortant.