4 Punkte von GN⁺ 2026-01-13 | 1 Kommentare | Auf WhatsApp teilen
  • Analysiert die strukturellen Grenzen und technischen Schulden des LLVM-Projekts aus verschiedenen Blickwinkeln und benennt konkret Bereiche mit Verbesserungsbedarf
  • Zeigt Engpässe beim Betrieb eines großen Open-Source-Projekts auf, darunter fehlende Reviews, API-Instabilität, Build- und Kompilierzeiten sowie instabile CI
  • Zu den Problemen im IR-Design zählen die Behandlung von undef-Werten, die Kodierung von Einschränkungen, die Semantik von Gleitkommazahlen und unvollständige Spezifikationen
  • Weist auf langfristige strukturelle Probleme hin, etwa Heterogenität der Backends, Verwirrung bei der ABI-Behandlung und verzögerte Migration von GlobalISel und Pass-Manager
  • Stellt LLVM nicht pauschal negativ dar, sondern als Chance für kontinuierliche Verbesserungen und breitere Beiträge

Wichtige strukturelle Probleme

  • Mangelnde Review-Kapazität wird als größter Engpass genannt

    • Es gibt viele Autoren, aber zu wenige Reviewer, sodass in manchen Fällen nicht ausreichend geprüfte Änderungen gemergt werden
    • Da Review-Anfragen in der Verantwortung der Autoren liegen, fällt es neuen Beitragenden schwer, die passenden Reviewer zu finden
    • Als mögliche Verbesserung wird die Einführung des automatischen PR-Zuweisungssystems von Rust genannt
  • Häufige Änderungen (Churn) an API und IR belasten die Nutzer

    • Die C-API ist vergleichsweise stabil, die C++-API ändert sich jedoch häufig, was die Wartungskosten für Frontends und Backends erhöht
    • Durch die Philosophie „Upstream or GTFO“ fließt nicht geteilter Code nicht in Entscheidungen ein
  • Problematisch sind die langen Build-Zeiten

    • LLVM besteht aus mehr als 2,5 Millionen Zeilen C++-Code, wodurch Builds sehr lange dauern; bei Debug-Builds steigen Speicher- und Festplattenverbrauch stark an
    • Als Verbesserungsansätze werden Precompiled Headers (PCH), dylib als Standard-Build und Daemonisierung von Tests diskutiert
  • Instabile CI

    • Mehr als 200 Buildbots testen in unterschiedlichen Umgebungen, können aber nicht dauerhaft einen „grünen Zustand“ halten
    • Flaky Tests und Probleme mit Buildbots verwässern Warnsignale, sodass echte Fehler schwer zu erkennen sind
    • Die Einführung von Tests vor dem PR-Merge hat teilweise geholfen, eine grundlegende Lösung fehlt jedoch weiterhin
  • Mangel an End-to-End-Tests

    • Unit-Tests für einzelne Optimierungen sind solide, aber Tests für die gesamte Pipeline oder die Integration mit Backends fehlen fast vollständig
    • llvm-test-suite existiert zwar, deckt grundlegende Kombinationen aus Operationen und Datentypen aber nicht ausreichend ab

Probleme bei Backends und Performance

  • Heterogenität zwischen Backends

    • Die mittleren Ebenen sind vereinheitlicht, bei den Backends gibt es jedoch viele targetspezifische Einzelanpassungen, was Duplizierung und Verzweigung erhöht
    • Statt gemeinsamer Optimierungen werden häufig target-spezifische Hooks ergänzt
  • Kompilierzeit

    • Langsam bei JITs und bei Sprachen, die große IR-Mengen erzeugen (Rust, C++)
    • -O0-Builds sind besonders langsam; das TPDE-Backend wird als bis zu 10- bis 20-mal schnellere Alternative genannt
  • Fehlendes Performance-Tracking

    • Es gibt keine offizielle Infrastruktur zur Verfolgung der Laufzeit-Performance
    • Das LNT-System ist wegen instabilem Betrieb, UX-Problemen und Datenmangel nur eingeschränkt wirksam

Probleme im IR-Design

  • Komplexe Behandlung von undef-Werten

    • Sie können bei jeder Verwendung einen anderen Wert annehmen und dadurch bei Optimierungen Fehler verursachen
    • Künftig könnten sie durch poison-Werte ersetzt werden, allerdings ist die Behandlung von poison im Speicher noch unzureichend
  • Unvollständige und inkonsistente Spezifikation

    • Es gibt seit Langem ungelöste Fehlverhaltensfälle
    • Hinzu kommen konzeptionell schwierige Probleme wie das Provenance-Modell
    • Zu deren Lösung wurde eine Arbeitsgruppe für formale Spezifikation eingerichtet
  • Fehlende Konsistenz bei der Kodierung von Einschränkungen

    • Poison-Flags, Metadaten, Attribute und Assumes werden in unterschiedlichen Formen parallel verwendet
    • Informationsverlust oder übermäßiger Erhalt von Informationen wirken sich negativ auf Optimierungen aus
  • Probleme bei der Gleitkomma-(FP-)Semantik

    • Bei signaling NaNs, nicht standardisierten Umgebungen, Denormal-Behandlung und x87-Überpräzision treten Inkonsistenzen auf
    • Die separate Behandlung über eingeschränkte FP-Intrinsics erhöht die Komplexität zusätzlich

Weitere technische Probleme

  • Verzögerte partielle Migrationen

    • Der neue Pass-Manager wird nur bis zur mittleren Ebene eingesetzt, Backends verwenden weiterhin die alte Variante
    • GlobalISel ist auch nach zehn Jahren nicht vollständig umgestellt und existiert parallel zu SDAG
  • Verwirrung bei ABI- und Calling-Convention-Behandlung

    • Die Aufgabentrennung zwischen Frontend und Backend ist unklar und schlecht dokumentiert
    • Die Einführung einer ABI-Bibliothek sowie ein Prototyp befinden sich in Arbeit
    • Es gibt zudem das Problem, dass sich die ABI je nach aktivierten Target-Features ändert
  • Inkonsistente Verwaltung von Built-in-Funktionen und libcalls

    • TargetLibraryInfo und RuntimeLibcalls sind getrennt, was zu mangelnder Konsistenz führt
    • Es gibt kein Bewusstsein für die Verfügbarkeit je nach Laufzeitbibliothekstyp (libgcc, compiler-rt usw.)
    • Es fehlen Anpassungspunkte für externe Laufzeiten wie Rust
  • Ineffiziente Context-/Module-Struktur

    • Typen und Konstanten liegen im Context, Funktionen und Globals im Module
    • Da kein Zugriff auf das Data Layout möglich ist, ist etwa Constant Folding umständlich
    • Kontextübergreifendes Linken ist nicht möglich; die Struktur muss vereinfacht werden
  • Registerdruck durch LICM (Loop-Invariant Code Motion)

    • Hoisting wird bedingungslos ohne Kostenmodell durchgeführt
    • Da das Backend nicht erneut sinkt, nehmen Spills und Reloads zu

Fazit

  • Die aufgelisteten Probleme sind strukturelle Herausforderungen, die aus Reifegrad und Größe von LLVM resultieren, und werden als Chance zur Verbesserung der Projektqualität und der Erfahrung von Beitragenden dargestellt
  • In einigen Bereichen (Build-Optimierung, ABI-Bibliothek, Performance-Tracking usw.) laufen bereits Verbesserungsarbeiten
  • Insgesamt ist LLVM weiterhin leistungsfähig, aber kontinuierliches Refactoring und eine Bereinigung der Spezifikation sind unerlässlich

1 Kommentare

 
GN⁺ 2026-01-13
Hacker-News-Kommentare
  • Der ganze Beitrag ist sehr gut strukturiert, daher kann ich vieles davon nachvollziehen.
    In letzter Zeit ist die Stabilität von LLVM IR ziemlich hoch geworden. Ich habe Fil-C an einem einzigen Tag von LLVM 17 auf 20 rebased.
    Auch in anderen Projekten habe ich denselben Pass über mehrere LLVM-Versionen hinweg beibehalten, ohne größere Probleme.
    Allerdings ist der Registerdruck durch LICM besonders bei Quellen, die nicht C/C++ sind, gravierend. Das Problem scheint weniger bei LICM selbst zu liegen, sondern eher darin, dass regalloc besser lernen müsste, zu rematerialize.

    • regalloc kennt rematerialize bereits. Nur hat das Backend im Vergleich zum Optimizer eben nur eine lokale Sicht, weshalb schlechte Entscheidungen von LICM nur schwer rückgängig zu machen sind.
    • Ein rematerialize-Pass existiert bereits. Man muss ihn nicht unbedingt an die Register Allocation koppeln. LLVM regalloc war ohnehin nie perfekt.
      Es wäre gut, mehr Optionen offenzulegen, damit Frontend-Entwickler verschiedene Einstellungen benchmarken und die besten Werte auswählen können.
    • Ich bin kein LLVM-Experte, aber als ich mich früher damit beschäftigt habe, fühlte sich das IR eher wie ein gemeinsames Vokabular mehrerer Sprachen an als wie eine einzelne Sprache.
      Jedes Tool und jede Komponente hat ihre eigenen Regeln, daher wirken Unterschiede zwischen Versionen eher natürlich. Ich frage mich, ob ich das vielleicht falsch verstanden habe.
  • Ich wollte LLVM 18 auf macOS bauen und bat den compiler-rt-Maintainer darum, nur ein einziges Boolean umzuschalten, aber das wurde als „heated“-Issue gesperrt und ist seit vier Jahren ungelöst.
    Trotzdem liebe ich LLVM weiterhin. clang-tidy, ASAN, UBSAN, LSAN, MSAN, TSAN sind wirklich hervorragend.
    Ich finde, beim Schreiben von C/C++-Code kein clang-tidy zu verwenden, ist eine falsche Entscheidung.
    Allerdings gibt es -fbounds-safety nur in AppleClang, und MSAN/LSAN nur in LLVM Clang. In Xcode fehlen außerdem clang-tidy, clang-format und llvm-symbolizer.
    Am Ende musste ich auf macOS Darwin LLVM selbst bauen und verwenden.
    Auch auf Linux ist die Lage verwirrend. RHEL liefert kein libcxx mit, Fedora schon. Aber ein für MSAN instrumentiertes libcxx gibt es in keiner Distribution.
    Fedora ist fast am Ziel, aber man muss compiler-rt immer noch manuell bauen.

    • Mir wurde empfohlen, Gentoo auszuprobieren. Siehe Gentoo-LLVM-Wiki.
    • Es kam auch die Frage auf, ob Chimera Linux oder Mandriva LLVM nicht standardmäßig gut unterstützen. Chimera ist ziemlich LLVM-nativ.
  • Nach den jüngsten LLVM-Diskussionen habe ich das Gefühl, dass unbedingt eine ausführbare Testsuite, die direkt bei LLVM IR beginnt, gebraucht wird und nicht bei C.
    Wenn man selbst ein Backend baut, fehlt es bei SelectionDAG und GlobalISel an Dokumentation, und die Semantik der Operationen ist unklar, sodass man leicht etwas falsch implementiert.

  • Die C API wirkt in LLVM wie ein vernachlässigtes Anhängsel. Viele Optionen oder opt-Pässe sind dort nicht verfügbar.

    • Das liegt daran, dass sich die Ausdrucksstärke der C++-API nur schwer in eine Schnittstelle im C-Stil übertragen lässt.
      Da die meisten Entwickler die C++-API direkt verwenden, rückt die C API nach hinten und bleibt am Ende ein Bürger zweiter Klasse.
  • Code-Review führt nicht zu unmittelbarer Belohnung, deshalb machen es die Leute nicht gern.
    Wenn man für Reviews ebenfalls Beitrags-Credits vergeben würde, könnte das motivierend wirken.

    • Ein ähnliches Problem haben wir auch innerhalb der Firma. Mein Unternehmen nimmt Qualität und Menge von Reviews in die Bewertung auf, aber selbst das ist noch kein ausreichender Anreiz.
  • Vor sechs Jahren habe ich LLVM oft auf einem Dell-9360-Laptop mit 8 GB RAM gebaut. Wenn man die Parallelität beim Linken reduziert, ging das innerhalb der Speichergrenzen.
    Ich frage mich, ob ein Build mit 8 GB heute noch möglich ist.

    • Wenn man parallele Builds abschaltet und ein paar GB Swap bereitstellt, geht es. Man muss allerdings Flags für die Linker-Konfiguration anpassen.
    • Auf einem M1 Mac wird LLVM mit allen Build-Einstellungen in weniger als einer Stunde kompiliert.
  • In den frühen Jahren von LLVM war die schnellere Kompiliergeschwindigkeit als bei GCC ein Vorteil.
    Ich frage mich, ob nach LLVM, jetzt 23 Jahre später, noch einmal etwas Neues entstehen wird.

    • Vor Kurzem gab es das TPDE-Projekt, das den -O0-Backend von LLVM um das 10- bis 20-Fache schneller gemacht hat, aber kaum Beachtung fand.
      Es gibt auch Alternativen wie Cranelift, das kein LLVM IR verwendet (Cranelift GitHub).
    • Trotzdem ist LLVM für die Kompilierung von C/C++ außerordentlich gut. Es ist nicht perfekt, aber um ein ähnliches Niveau zu erreichen, braucht man zehntausende Personenstunden an Aufwand.
  • Der größte Schmerzpunkt ist die Behandlung von ABI und Calling Conventions.
    Im Compiler-Frontend muss man die Argumentübergabe selbst verwalten und manchmal sogar die Anzahl der Register berechnen.

  • Im Artikel heißt es, „Frontends werden durch eine stabile C API geschützt“, aber in Wirklichkeit stimmt das nicht.
    Einige APIs sind stabil, aber Bereiche wie Orc ändern sich häufig.

    • Die Orc-C-API folgt anderen Regeln als die übrigen C-APIs (Orc.h-Quelllink).
  • LLVM scheint praktisch kein System zur Review von Issues zu haben. Auch meine eingereichten Bug-Reports werden seit Jahren nicht bearbeitet.