4 puntos por GN⁺ 2026-01-13 | 1 comentarios | Compartir por WhatsApp
  • Analiza desde múltiples ángulos las limitaciones estructurales y la deuda técnica del proyecto LLVM, y señala de forma concreta las áreas que necesitan mejoras
  • Presenta cuellos de botella en la operación de un gran proyecto open source, como falta de revisión, inestabilidad de la API, tiempos de build y compilación, e inestabilidad del CI
  • Entre los problemas de diseño del IR se incluyen el manejo de valores undef, la codificación de restricciones, la semántica de punto flotante y la incompletitud de la especificación
  • Señala problemas estructurales de largo plazo, como la heterogeneidad de los backends, la confusión en el manejo del ABI y el retraso en la migración de GlobalISel y del pass manager
  • Más que presentar el estado de LLVM de forma negativa, lo plantea como una oportunidad para la mejora continua y para ampliar las contribuciones

Problemas estructurales principales

  • La falta de capacidad de revisión se señala como el mayor cuello de botella

    • Hay muchos autores de código, pero faltan revisores, por lo que a veces se fusionan cambios sin suficiente validación
    • Como la estructura hace que pedir revisión sea responsabilidad del autor, a los nuevos contribuidores les resulta difícil encontrar revisores adecuados
    • Se menciona como posible mejora la adopción del sistema de asignación automática de PRs de Rust
  • Los cambios frecuentes (churn) en la API y el IR cargan a los usuarios

    • La API de C es relativamente estable, pero la API de C++ cambia con frecuencia, aumentando el costo de mantenimiento de frontends y backends
    • La filosofía de “Upstream or GTFO” hace que el código no compartido no se refleje en la toma de decisiones
  • Problema de tiempos de build excesivos

    • LLVM está compuesto por más de 2.5 millones de líneas de código C++, por lo que el build tarda mucho; en builds de depuración también se disparan el uso de memoria y disco
    • Se discuten como mejoras posibles los headers precompilados (PCH), el build por defecto como dylib y la daemonización de pruebas
  • Inestabilidad del CI

    • Más de 200 buildbots prueban en entornos diversos, pero no se logra mantener siempre un “estado verde”
    • Las pruebas flaky y los problemas de los buildbots diluyen las señales de alerta, dificultando detectar errores reales
    • La introducción de pruebas previas para PRs ha mejorado algo la situación, pero la solución de fondo sigue siendo insuficiente
  • Falta de pruebas end-to-end

    • Las pruebas unitarias de optimizaciones individuales son sólidas, pero casi no hay pruebas del pipeline completo ni de integración con backends
    • Existe llvm-test-suite, pero no cubre suficientemente combinaciones básicas de operaciones y tipos de datos

Problemas relacionados con backend y rendimiento

  • Heterogeneidad entre backends

    • Aunque las etapas intermedias están unificadas, en los backends hay muchas modificaciones independientes por objetivo, lo que aumenta la duplicación y la divergencia
    • Existe la tendencia a agregar hooks específicos por objetivo en vez de optimizaciones comunes
  • Tiempo de compilación

    • Es lento en JIT y en lenguajes que generan IR a gran escala, como Rust y C++
    • Los builds con -O0 son especialmente lentos, y el backend TPDE se presenta como una alternativa hasta 10~20 veces más rápida
  • Ausencia de seguimiento de rendimiento

    • No existe una infraestructura oficial para rastrear el rendimiento en tiempo de ejecución
    • El sistema LNT tiene problemas de inestabilidad operativa, UX y falta de datos, por lo que su efectividad es baja

Problemas de diseño del IR

  • Complejidad en el manejo de valores undef

    • Pueden tener un valor distinto en cada uso, lo que provoca errores durante las optimizaciones
    • En el futuro podrían reemplazarse por valores poison, pero el manejo de poison en memoria aún está incompleto
  • Incompletitud e inconsistencias de la especificación

    • Existen casos antiguos de mal funcionamiento que siguen sin resolverse
    • Persisten retos de diseño como el modelo de provenance
    • Para abordar esto se formó un grupo de trabajo de especificación formal
  • Falta de consistencia en la codificación de restricciones

    • Se mezclan distintos métodos, como flags poison, metadata, atributos y assumes
    • La pérdida de información o su conservación excesiva afecta negativamente a las optimizaciones
  • Problemas en la semántica de punto flotante (FP)

    • Se producen inconsistencias con NaN con señal, entornos no estándar, manejo de denormals y precisión extendida de x87
    • Al tratarse aparte mediante intrinsics FP restringidos, aumenta la complejidad

Otros problemas técnicos

  • Retrasos en migraciones parciales

    • El nuevo pass manager solo se aplica hasta las etapas intermedias; los backends siguen usando el anterior
    • GlobalISel no ha logrado una transición completa en 10 años y coexiste con SDAG
  • Confusión en el manejo del ABI y las calling conventions

    • La separación de responsabilidades entre frontend y backend no está clara y hay poca documentación
    • Está en marcha la introducción de una biblioteca ABI y su implementación prototipo
    • También existe el problema de que el ABI cambie según se activen ciertas funciones del objetivo
  • Inconsistencia en la gestión de builtins y libcalls

    • TargetLibraryInfo y RuntimeLibcalls están separados, lo que reduce la consistencia
    • No se puede reconocer la disponibilidad según el tipo de runtime library (libgcc, compiler-rt, etc.)
    • Falta un punto de personalización para runtimes externos como Rust
  • Ineficiencia de la estructura Context / Module

    • Los tipos y constantes viven en Context, mientras que las funciones y globales están en Module
    • La falta de acceso al data layout genera incomodidades en tareas como el constant folding
    • No se pueden enlazar contextos cruzados, por lo que hace falta simplificar la estructura
  • Presión de registros causada por LICM (movimiento de código invariante de bucle)

    • Se hace hoist sin un modelo de costos
    • Como el backend no vuelve a hacer sink, aumentan los spills y reloads

Conclusión

  • Los problemas enumerados son retos estructurales derivados de la madurez y escala de LLVM, y se presentan como una oportunidad para mejorar la calidad del proyecto y la experiencia de los contribuidores
  • En algunas áreas, como la optimización del build, la biblioteca ABI y el seguimiento de rendimiento, ya hay trabajos de mejora en curso
  • En conjunto, LLVM sigue siendo poderoso, pero el refactoring continuo y el ajuste de la especificación son indispensables

1 comentarios

 
GN⁺ 2026-01-13
Comentarios en Hacker News
  • El texto en general está bien organizado, así que coincido bastante.
    Últimamente la estabilidad de LLVM IR ha mejorado bastante. Rebasé Fil-C de LLVM 17 a 20 en un solo día.
    En otros proyectos también mantuve el mismo pass en varias versiones de LLVM y no hubo mayores problemas.
    Aun así, la presión de registros en LICM es especialmente grave en fuentes que no son C/C++. El problema parece menos de LICM en sí y más de lograr que regalloc aprenda mejor a rematerialize

    • regalloc ya conoce rematerialize. Pero como el backend solo tiene una visión local en comparación con el optimizador, le cuesta revertir malas decisiones tomadas por LICM
    • El pass de rematerialize ya existe. No hace falta atarlo al register allocation. El regalloc de LLVM tampoco ha sido perfecto desde el principio.
      Estaría bien abrir más opciones para que quienes desarrollan frontends puedan hacer benchmarks con distintas configuraciones y elegir el valor óptimo
    • No soy experto en LLVM, pero cuando lo toqué hace tiempo, el IR me pareció más un vocabulario común para varios lenguajes que un lenguaje en sí.
      Como cada herramienta y componente tiene sus propias reglas, hasta parece natural que haya diferencias entre versiones. Me pregunto si lo habré entendido mal
  • Cuando intenté compilar LLVM 18 en macOS, le pedí a la persona a cargo de compiler-rt que cambiara un solo boolean, pero el issue se cerró por estar “heated” y sigue sin resolverse desde hace 4 años.
    Aun así, sigo queriendo a LLVM. clang-tidy, ASAN, UBSAN, LSAN, MSAN, TSAN son realmente excelentes.
    Creo que escribir código C/C++ sin usar clang-tidy es una mala decisión.
    Pero -fbounds-safety solo está en AppleClang, y MSAN/LSAN solo están en LLVM Clang. Xcode tampoco trae clang-tidy, clang-format ni llvm-symbolizer.
    Al final, en macOS terminé teniendo que compilar Darwin LLVM por mi cuenta para usarlo.
    Del lado de Linux también hay confusión. RHEL no trae libcxx, pero Fedora sí. Sin embargo, ninguna distribución trae libcxx instrumentada para MSAN.
    Fedora casi llega, pero todavía hay que compilar compiler-rt manualmente

    • Me recomendaron probar Gentoo. Ver la wiki de LLVM en Gentoo
    • También hubo quien preguntó si Chimera Linux o Mandriva no hacen que LLVM funcione bien por defecto. Chimera es bastante nativa de LLVM
  • Después de pasar por discusiones recientes sobre LLVM, sentí que hace mucha falta una suite de pruebas ejecutables que parta de LLVM IR, no de C.
    Si uno construye un backend directamente, falta documentación sobre SelectionDAG o GlobalISel, y el significado de varias operaciones no es claro, así que es fácil implementar mal las cosas

  • La API de C se siente como algo dejado de lado dentro de LLVM. Muchas opciones o passes de opt no están expuestos.

    • Esto se debe a que la capacidad expresiva de la API de C++ es difícil de trasladar a una interfaz estilo C.
      Como la mayoría de quienes desarrollan usan directamente la API de C++, la API de C queda relegada y termina siendo una ciudadana de segunda
  • Como el code review no se traduce en una recompensa inmediata, la gente tiende a no hacerlo mucho.
    Si también se diera crédito de contribución por revisar, probablemente habría más motivación.

    • En mi empresa pasa algo parecido. Incluyen la calidad y cantidad de reviews como criterio de evaluación, pero aun así no alcanza para motivar lo suficiente
  • Hace 6 años compilaba LLVM seguido en una laptop Dell 9360 con 8 GB de RAM. Reduciendo el paralelismo del enlazado se podía hacer dentro del límite de memoria.
    Me pregunto si hoy todavía se puede compilar con 8 GB.

    • Sí se puede si desactivas la compilación paralela y aseguras unos cuantos GB de swap. Eso sí, hay que ajustar los flags de configuración del linker
    • En una Mac M1, LLVM compila en menos de una hora con cualquier configuración de build
  • En los primeros días de LLVM, una de sus ventajas era la velocidad de compilación más rápida que GCC.
    Ahora, 23 años después de LLVM, me pregunto si aparecerá algo nuevo otra vez.

    • Hace poco alguien presentó el proyecto TPDE, que hacía el backend de -O0 de LLVM entre 10 y 20 veces más rápido, pero no recibió mucha atención.
      También hay alternativas como Cranelift, que no usa LLVM IR (Cranelift GitHub)
    • Aun así, LLVM sigue siendo excelente para compilar C/C++. No es perfecto, pero para lograr algo de nivel parecido hacen falta decenas de miles de horas-persona
  • El manejo del ABI y las convenciones de llamada es el mayor dolor.
    En el frontend del compilador hay que gestionar directamente el paso de argumentos y, a veces, incluso calcular la cantidad de registros

  • En el texto se decía que “los frontends están protegidos gracias a una API de C estable”, pero en la práctica no es así.
    Algunas APIs sí son estables, pero partes como Orc cambian con frecuencia.

    • La API de C de Orc sigue reglas distintas a las de otras APIs de C (fuente de Orc.h)
  • Parece que LLVM casi no tiene un sistema de revisión de issues. Los reportes de bugs que envié también llevan años sin ser atendidos.