Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

  1. #1
    Responsable Qt & Livres

    LLVM réfléchit à l'implémentation native des matrices
    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.
    Vous souhaitez participer aux rubriques Qt ou PyQt (tutoriels, FAQ, traductions), HPC ? Contactez-moi par MP.

    Créer des applications graphiques en Python avec PyQt5
    Créer des applications avec Qt 5.

    Pas de question d'ordre technique par MP !

  2. #2
    Membre du Club
    C’est pas trop tôt
    Ayant codé des calculs matriciels en fortran + MPI/OpenMP sur 64 processeurs en 2000, je doit avouer que j’ai été décontenancé de voir que les langages pour les cartes graphiques n’avaient pas à leur sortie de méta-structure de type «matrice» autre que du 4x4.
    En 2000, arriver aux performances du compilateur fortran pour le calcul matriciel était extrêmement compliqué (surtout face à la simplicité du programme écrit en Fortran, à peine décoré de quelques directives pour donner des indices au compilateur concernant ce qui était à paralléliser et ce qui était constant ou variable), donc je me suis limité à ce compilateur (alors que sur plein d’autres programmes classiques, le portage en C avait amené de meilleures performances).

    Si la LLVM le prend en compte, c’est un bon début, mais ensuite il faudra ajouter ce genre de primitives au niveau des langages et enfin que les programmeurs s’en emparent… Ça ne me semble pas pour tout de suite!