4 points par GN⁺ 2026-01-13 | 1 commentaires | Partager sur WhatsApp
  • 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 dylib par 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-suite existe, 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 -O0 sont 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 de poison en 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
  • 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

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

1 commentaires

 
GN⁺ 2026-01-13
Avis sur Hacker News
  • Le texte est globalement bien structuré, et je m’y retrouve beaucoup.
    Ces derniers temps, la stabilité de LLVM IR est devenue assez élevée. J’ai rebasé Fil-C de LLVM 17 à 20 en une seule journée.
    Dans d’autres projets aussi, j’ai maintenu le même pass sur plusieurs versions de LLVM sans gros problème.
    En revanche, la pression sur les registres de LICM est particulièrement sévère pour des sources autres que C/C++. Le problème semble moins venir de LICM lui-même que du fait qu’il faudrait apprendre à regalloc à mieux rematérialiser

    • regalloc sait déjà rematérialiser. Mais comme le backend n’a qu’une vision locale par rapport à l’optimiseur, il lui est difficile d’annuler les mauvaises décisions prises par LICM
    • Un pass de rematérialisation existe déjà. Il n’est pas nécessaire de le coupler à la register allocation. La regalloc de LLVM n’a jamais été parfaite de toute façon
      Ce serait bien d’ouvrir davantage d’options pour que les développeurs de frontend puissent benchmarker différents réglages et choisir la meilleure valeur
    • Je ne suis pas un expert LLVM, mais quand j’y ai touché autrefois, l’IR m’a donné l’impression d’être moins un langage qu’un vocabulaire commun à plusieurs langages.
      Chaque outil et composant a ses propres règles, donc il semble presque naturel qu’il y ait des différences entre versions. Je me demande si je comprends mal quelque chose
  • J’ai essayé de compiler LLVM 18 sur macOS et j’ai demandé au responsable de compiler-rt de ne changer qu’un booléen, mais l’issue a été verrouillée comme discussion « heated » et cela reste non résolu depuis 4 ans
    Malgré ça, j’adore toujours LLVM. clang-tidy, ASAN, UBSAN, LSAN, MSAN, TSAN sont vraiment excellents.
    À mon avis, ne pas utiliser clang-tidy quand on écrit du code C/C++ est un mauvais choix
    En revanche, -fbounds-safety n’existe que dans AppleClang, tandis que MSAN/LSAN n’existent que dans LLVM Clang. Xcode n’inclut pas non plus clang-tidy, clang-format ni llvm-symbolizer.
    Au final, sur macOS, j’ai dû compiler moi-même Darwin LLVM pour l’utiliser.
    Côté Linux aussi, c’est confus. RHEL ne fournit pas libcxx, mais Fedora oui. En revanche, aucune distribution ne fournit un libcxx instrumenté pour MSAN
    Fedora y est presque, mais il faut encore compiler compiler-rt à la main

    • On m’a conseillé d’essayer Gentoo. Voir le wiki LLVM de Gentoo
    • Certains ont aussi demandé si Chimera Linux ou Mandriva ne faisaient pas déjà bien fonctionner LLVM par défaut. Chimera est assez LLVM native
  • Après les discussions récentes autour de LLVM, j’ai le sentiment qu’il faut absolument une suite de tests exécutable qui commence directement à partir de LLVM IR, pas de C
    Quand on implémente soi-même un backend, la documentation sur SelectionDAG ou GlobalISel est insuffisante, et le sens des opérations manque de clarté, ce qui rend les erreurs d’implémentation faciles

  • La C API donne l’impression d’être laissée de côté dans LLVM. Beaucoup d’options ou de pass opt ne sont pas exposés

    • Cela vient du fait que la richesse expressive de l’API C++ est difficile à transposer dans une interface de style C.
      Comme la plupart des développeurs utilisent directement l’API C++, la C API passe après tout le reste et finit par rester un citoyen de seconde zone
  • Les revues de code n’apportent pas de récompense immédiate, donc les gens ont tendance à ne pas en faire
    Donner aussi du crédit de contribution pour les reviews pourrait créer une motivation

    • On rencontre un problème similaire en entreprise. Ma société inclut la qualité et la quantité des reviews dans l’évaluation, mais cela ne suffit toujours pas à motiver vraiment
  • Il y a 6 ans, je compilais souvent LLVM sur un Dell 9360 avec 8 Go de RAM. En réduisant le parallélisme à l’édition de liens, ça passait dans la limite mémoire
    Je me demande si compiler avec 8 Go reste possible aujourd’hui

    • Oui, si on désactive la compilation parallèle et qu’on prévoit quelques Go de swap. En revanche, il faut ajuster les flags de configuration du linker
    • Sur un Mac M1, LLVM se compile en moins d’une heure avec n’importe quelle configuration de build
  • Au tout début, LLVM avait pour avantage une vitesse de compilation supérieure à GCC.
    Maintenant que 23 ans ont passé depuis l’arrivée de LLVM, je me demande si quelque chose de nouveau apparaîtra encore

    • Récemment, quelqu’un a présenté le projet TPDE, qui rend le backend -O0 de LLVM 10 à 20 fois plus rapide, mais cela n’a pas attiré l’attention
      Il existe aussi des alternatives comme Cranelift, qui n’utilise pas LLVM IR (Cranelift GitHub)
    • Malgré tout, LLVM reste excellent pour compiler du C/C++. Ce n’est pas parfait, mais atteindre un niveau comparable demanderait des dizaines de milliers d’heures-homme
  • La gestion de l’ABI et des conventions d’appel est la plus grande source de douleur.
    Il faut gérer soi-même le passage des arguments dans le frontend, et parfois aller jusqu’à compter le nombre de registres

  • L’article disait que « les frontends sont protégés grâce à une C API stable », mais en pratique ce n’est pas vrai
    Certaines API sont stables, mais des parties comme Orc changent souvent

    • La C API d’Orc suit des règles différentes des autres C API (source Orc.h)
  • LLVM donne l’impression de n’avoir pratiquement aucun système de revue des issues. Les rapports de bugs que j’ai soumis moi aussi ne sont toujours pas traités après plusieurs années