LLVM : les points faibles
(npopov.com)- Analyse sous plusieurs angles des limites structurelles et de la dette technique du projet LLVM, en pointant concrètement les domaines à améliorer
- Présentation des goulets d’étranglement dans l’exploitation d’un grand projet open source, comme le manque de revue, l’instabilité des API, les temps de build et de compilation, ou encore l’instabilité de la CI
- Parmi les problèmes de conception de l’IR, l’article cite la gestion des valeurs
undef, l’encodage des contraintes, la sémantique en virgule flottante et l’incomplétude de la spécification - Il relève aussi des problèmes structurels de long terme, comme l’hétérogénéité des backends, la confusion autour de la gestion de l’ABI, et les retards de transition de GlobalISel et du pass manager
- Plutôt que de dresser un constat négatif sur LLVM, l’article présente ces sujets comme une opportunité d’amélioration continue et d’élargissement des contributions
Principaux problèmes structurels
-
Le manque de capacité de revue est présenté comme le principal goulet d’étranglement
- Il y a beaucoup d’auteurs de code, mais pas assez de relecteurs, ce qui conduit parfois à l’intégration de modifications insuffisamment vérifiées
- Comme la demande de revue repose sur l’auteur, les nouveaux contributeurs ont du mal à trouver les bons relecteurs
- L’adoption d’un système d’attribution automatique des PR comme celui de Rust est évoquée comme piste d’amélioration
-
Les changements fréquents (churn) des API et de l’IR pèsent sur les utilisateurs
- L’API C reste relativement stable, mais l’API C++ change souvent, ce qui augmente les coûts de maintenance des frontends et des backends
- La philosophie « Upstream or GTFO » fait que le code non partagé n’est pas pris en compte dans les décisions
-
Le problème des temps de build excessifs
- LLVM se compose de plus de 2,5 millions de lignes de code C++, ce qui allonge fortement les builds, avec une forte hausse de l’usage mémoire et disque en build debug
- Des pistes comme les en-têtes précompilés (PCH), le build en
dylibpar défaut ou la daemonisation des tests sont discutées
-
Instabilité de la CI
- Plus de 200 buildbots testent divers environnements, mais l’état « vert » n’est pas maintenu en permanence
- Les tests flaky et les problèmes de buildbots diluent les signaux d’alerte, ce qui rend la détection des erreurs réelles plus difficile
- L’introduction de tests avant PR a permis quelques améliorations, sans résoudre le problème de fond
-
Manque de tests end-to-end
- Les tests unitaires d’optimisation sont solides, mais il existe très peu de tests du pipeline complet ou d’intégration backend
llvm-test-suiteexiste, mais ne couvre pas suffisamment les combinaisons d’opérations de base et de types de données
Problèmes liés aux backends et aux performances
-
Hétérogénéité entre les backends
- Les couches intermédiaires sont unifiées, mais les backends accumulent de nombreuses modifications propres à chaque cible, ce qui accroît les duplications et divergences
- Il existe une tendance à ajouter des hooks spécifiques à une cible plutôt qu’à généraliser les optimisations communes
-
Temps de compilation
- LLVM est lent pour les JIT et pour les langages qui génèrent de gros volumes d’IR comme Rust ou C++
- Les builds en
-O0sont particulièrement lents, et le backend TPDE est présenté comme une alternative jusqu’à 10 à 20 fois plus rapide
-
Absence de suivi des performances
- Il n’existe pas d’infrastructure officielle de suivi des performances d’exécution
- Le système LNT souffre d’instabilité, de problèmes d’UX et d’un manque de données, ce qui limite fortement son utilité
Problèmes de conception de l’IR
-
Complexité de la gestion des valeurs
undef- Elles peuvent prendre une valeur différente à chaque utilisation, ce qui provoque des erreurs lors des optimisations
- Elles pourraient à terme être remplacées par des valeurs
poison, mais la gestion depoisonen mémoire reste incomplète
-
Spécification incomplète et incohérente
- Il existe d’anciens cas de mauvais fonctionnement toujours non résolus
- Des difficultés de conception persistent, comme le modèle de provenance
- Pour y répondre, un groupe de travail sur la spécification formelle a été mis en place
-
Manque de cohérence dans l’encodage des contraintes
- Drapeaux
poison, métadonnées, attributs,assumes: plusieurs approches coexistent - Cette situation nuit aux optimisations, soit par perte d’information, soit par conservation excessive d’informations
- Drapeaux
-
Problèmes de sémantique en virgule flottante (FP)
- Des incohérences apparaissent avec les NaN signalants, les environnements non standard, la gestion des denormals ou la précision étendue du x87
- Le traitement séparé via des intrinsic FP contraints ajoute encore de la complexité
Autres problèmes techniques
-
Retards dans certaines migrations partielles
- Le nouveau pass manager n’est appliqué qu’aux couches intermédiaires, tandis que les backends utilisent encore l’ancien
- GlobalISel n’a toujours pas remplacé complètement SDAG après 10 ans et coexiste avec lui
-
Confusion autour de la gestion de l’ABI et des conventions d’appel
- La répartition des responsabilités entre frontend et backend manque de clarté, et la documentation est insuffisante
- L’introduction d’une bibliothèque ABI et une implémentation prototype sont en cours
- Le problème existe aussi lorsque l’ABI varie selon l’activation de fonctionnalités de la cible
-
Gestion incohérente des fonctions builtin et des libcalls
- TargetLibraryInfo et RuntimeLibcalls sont séparés, ce qui nuit à la cohérence
- LLVM ne peut pas déterminer la disponibilité selon le type de bibliothèque d’exécution (
libgcc,compiler-rt, etc.) - Il manque des points de personnalisation pour des runtimes externes comme celui de Rust
-
Inefficacité de la structure Context / Module
- Les types et constantes résident dans le Context, tandis que les fonctions et globales sont dans le Module
- L’absence d’accès au data layout complique des opérations comme le constant folding
- L’impossibilité de lier entre contextes différents montre la nécessité de simplifier la structure
-
Pression sur les registres due à LICM (loop invariant code motion)
- Le déplacement (
hoist) est effectué systématiquement sans modèle de coût - Le backend ne refait pas ensuite de déplacement inverse (
sink), ce qui augmente les spill/reload
- Le déplacement (
Conclusion
- Les problèmes énumérés relèvent de défis structurels issus de la maturité et de l’ampleur de LLVM,
présentés comme une opportunité d’améliorer la qualité du projet et l’expérience des contributeurs - Dans certains domaines, comme l’optimisation des builds, la bibliothèque ABI ou le suivi des performances, des améliorations sont déjà en cours
- Dans l’ensemble, LLVM reste très puissant, mais un refactoring continu et une mise à niveau de la spécification restent indispensables
Aucun commentaire pour le moment.