Un compilateur est souvent divisé en deux parties distinctes : une partie avant, qui lit un code source ; une partie arrière, qui écrit un code binaire pour une architecture donnée. Ces deux parties communiquent à l'aide d'une représentation intermédiaire (IR), sur laquelle bon nombre d'optimisations peuvent être effectuées. Un tel découpage facilite l'implémentation de nouveaux langages ou le ciblage de nouvelles plateformes. Pour qu'il soit efficace, le compilateur doit reposer sur une représentation intermédiaire de qualité, à un niveau d'abstraction bien choisi : ni trop élevée (l'IR correspondrait à un langage de programmation complet), ni trop basse (l'IR serait alors un assembleur pour une architecture précise). L'IR doit être un compromis entre une grande possibilité d'optimisation du code, une simplicité d'écriture du générateur de code binaire (qui a déjà beaucoup de choses à gérer avec les détails de l'architecture cible, comme l'utilisation des registres du processeur ou les optimisations spécifiques) et une indépendance de la plateforme ciblée (pour que les optimisations effectuées sur l'IR soient utiles à plusieurs plateformes).
La représentation intermédiaire LLVM IR est utilisée par la famille de compilateurs de l'écosystème LLVM, comme Clang ou Flang. Ses développeurs la décrivent comme un langage d'assemblange pour une plateforme virtuelle (d'où l'acronyme LLVM : low-level virtual machine), avec toutefois la notion de fonction (ce qui permet notamment d'écrire une valeur de retour : la gestion des conventions d'appel peut alors dépendre de la plateforme cible, ce qui est par exemple le cas en C et C++). Elle dispose d'une série de types de base : des scalaires, évidemment, des agrégats, c'est-à-dire des ensembles de valeurs stockées ensemble (comme une structure ou un objet), mais aussi des vecteurs à longueur fixe ou variable, qui servent à donner aux passes d'optimisation autant d'informations que possible sur le code (et donc à générer un code binaire aussi efficace que possible, in fine, avec l'utilisation des instructions SIMD disponibles sur le processeur visé).
Dès 2018, certains développeurs d'Apple travaillant sur LLVM proposent d'ajouter un nouveau type de structure de données dans cette représentation intermédiaire : les matrices. L'IR disposerait aussi d'une série de fonctions intrinsèques pour travailler sur ces matrices, comme l'extraction et la mise à jour d'une valeur, un produit entre matrices ou entre une matrice et un vecteur. L'avantage serait d'apporter plus d'informations au générateur de code binaire : le compilateur pourrait alors fournir de bien meilleures garanties de vectorisation du code (voire d'utilisation des instructions matricielles, par exemple celles présentes dans l'architecture ARM v8.6) ; de même, il pourrait s'arranger pour éviter des écritures en mémoire trop fréquentes, laissant les valeurs nécessaires dans les registres du processeur. Il pourrait aussi décider de la meilleure manière de représenter la matrice en mémoire : soit ligne par ligne, soit colonne par colonne, soit comme une matrice creuse, selon le type d'accès le plus fréquent. Le générateur de code pourrait aussi décider de remplir la mémoire entre les lignes ou les colonnes, de telle sorte que chaque ligne ou chaque colonne soit bien alignée.
En détail, la proposition porte sur quatre types de fonction intrinsèques : transposition, multiplication, lecture et écriture (y compris avec décalages). L'idée d'un type entièrement spécifique aux matrices n'a pas été très appréciée de tous les développeurs (à cause de la complexité de l'opération), c'est pourquoi elles sont plutôt implémentées comme des vecteurs : les dimensions de la matrice sont passées en argument aux fonctions intrinsèques.
Clang suit assez rapidement la tendance et prévoit déjà d'utiliser ces nouvelles fonctionnalités. Les matrices seraient indiquées par un attribut, matrix_type(lignes, colonnes), où les dimensions de la matrice seraient constantes ; cet attribut porterait sur une variable de type tableau, contenant au moins autant d'éléments que la matrice déclarée. Le compilateur fournirait une série d'opérations intégrées correspondant aux fonctions intrinsèques.
Source : liste de diffusion LLVM (proposition d'origine, proposition reformulée, détails d'implémentation pour Clang), premier commit.
LLVM réfléchit à l'implémentation native des matrices pour faciliter les optimisations sur du code matriciel
Clang suit de près avec de nouvelles fonctions intégrées
LLVM réfléchit à l'implémentation native des matrices pour faciliter les optimisations sur du code matriciel
Clang suit de près avec de nouvelles fonctions intégrées
Le , par dourouc05
Une erreur dans cette actualité ? Signalez-nous-la !