1 puntos por GN⁺ 2025-06-09 | 1 comentarios | Compartir por WhatsApp
  • Zig cambió la ruta predeterminada en objetivos x86_64, donde LLVM bajaba bitcode a archivos objeto, por su backend x86 autoalojado, reduciendo de forma importante la velocidad de compilación y el uso de memoria en builds de depuración
  • El backend x86 autoalojado pasa 1987 behavior tests, más que los 1980 del backend de LLVM, y algunas pruebas adicionales de un total de 2084 solo se ejecutan en las pruebas de x86 autoalojado
  • En el benchmark de hello.zig, el promedio de 918ms de la ruta con LLVM bajó a 275ms con el backend autoalojado predeterminado, lo que reduce el wall time en 70.1%, y el peak RSS también baja de 214MB a 137MB
  • Incluso en proyectos grandes como el propio compilador Zig, el tiempo de build se redujo de 75 segundos a 20 segundos, aunque Windows todavía no entra en este cambio predeterminado porque el COFF linker aún requiere más trabajo
  • El trabajo pendiente incluye paralelización completa de la generación de código, mejoras del linker, estabilización de la compilación incremental, mejora de la calidad del código x86 y expansión del backend aarch64

Cambio del backend predeterminado en x86_64

  • En builds para objetivos x86_64, Zig ahora usa por defecto su backend x86 autoalojado
  • La ruta predeterminada anterior consistía en que LLVM bajara archivos bitcode a archivos objeto
  • En Windows, el valor predeterminado todavía no cambia
    • Esto se debe a que aún hace falta más trabajo en el COFF linker

Estado de los behavior tests superados

  • El backend x86 autoalojado supera 1987 behavior tests
  • El backend de LLVM supera 1980 behavior tests
  • El total de behavior tests es 2084, pero las pruebas adicionales en su mayoría se superponen con las pruebas del backend x86 propio de LLVM
    • Estas pruebas adicionales solo se ejecutan durante las pruebas de x86 autoalojado
  • Medido por cantidad de pruebas superadas, el backend x86 de Zig ya va por delante del backend de LLVM en la implementación del lenguaje Zig

Por qué compite con la ruta de LLVM

  • La razón principal por la que Zig compite con LLVM en generación de código es que puede marcar una gran diferencia en la velocidad de compilación
  • El contexto relacionado está resumido en la explicación en Ziggit

Benchmark de hello.zig

  • Resultado de zig build-exe hello.zig -fllvm:
    • wall time promedio: 918ms
    • peak RSS: 214MB
    • CPU cycles: 4.53G
    • instructions: 8.50G
  • Resultado de la ruta predeterminada con zig build-exe hello.zig:
    • wall time promedio: 275ms
    • peak RSS: 137MB
    • CPU cycles: 1.57G
    • instructions: 3.21G
  • El backend autoalojado predeterminado reduce varias métricas frente a la ruta con LLVM
    • wall time 70.1% menos
    • peak RSS 36.2% menos
    • CPU cycles 65.2% menos
    • instructions 62.2% menos
    • cache misses 86.1% menos
    • branch misses 78.3% menos

Efecto en proyectos grandes

  • En proyectos más grandes, como el propio compilador Zig, el tiempo de build baja de 75 segundos a 20 segundos
  • El backend x86 autoalojado puede reducir de forma importante el tiempo de compilación no solo en ejemplos pequeños, sino también en codebases grandes

Próximo trabajo

  • Zig ya comenzó el trabajo de paralelización completa de la generación de código
  • A medida que avancen las mejoras del linker y las correcciones de errores, será posible hacer que la compilación incremental sea estable y robusta junto con este backend
  • La calidad del código x86 generado todavía tiene margen de mejora
  • El siguiente objetivo es aarch64, y se espera que el trabajo se acelere gracias al nuevo Legalize pass
  • Se puede descargar y probar directamente la build más reciente de la rama master desde la página de descargas de Zig

1 comentarios

 
GN⁺ 2025-06-09
Comentarios de Hacker News
  • Por lo que sé, Zig tiene mucho trabajo en curso para mejorar la experiencia de desarrollo. Casi todos los días se trabaja en algo, y justo acaba de aparecer algo como https://github.com/ziglang/zig/pull/24124
    Tengo entendido que antes también estaba planeado el reemplazo de código en caliente, y al ritmo actual de desarrollo no me sorprendería que funcione en x86_64 dentro de un año
    Ahora mismo, personalmente, mi mayor dolor es la velocidad de comptime. El compilador tiene mucho que hacer ahí, y ejecutar un DSL brainF** en tiempo de compilación es bastante lento. Lo probé yo mismo y fue un experimento gracioso
    En general me entusiasman mucho los nuevos backends que Zig está incorporando. Me gustaría intentar hacer yo mismo un backend URCL(https://github.com/ModPunchtree/URCL) para Zig

    • Se sabe qué hay que hacer para mejorar el rendimiento de comptime, y hace tiempo incluso se empezó a trabajar en una rama. Pero requiere retrabajar bastante el código de análisis semántico, así que sin duda se puede hacer, se debe hacer y se hará, pero compite con otras prioridades
    • El reemplazo de código en caliente sería enorme para el desarrollo de juegos. La idea de que Zig vaya a soportarlo básicamente de forma nativa con una sola bandera del compilador es impresionante. Me gustaría ver a alguien intentar hacerlo con clang
    • Me pregunto si que comptime sea lento es realmente un problema. Estoy creando una biblioteca JSON-RPC y dependo mucho de comptime para despachar solicitudes JSON a funciones arbitrarias
      Debido al tipado estático estricto, no hay forma de hacer despacho dinámico en runtime hacia una función con parámetros arbitrarios, y la única forma que encontré fue averiguar en tiempo de compilación, con comptime, el mapeo de tipos de función
      Supongo que el tamaño del código crecerá porque aumenta la cantidad de copias de código hechas con comptime por cada función arbitraria
    • Me pregunto si es fácil crear un backend personalizado. Todavía no lo he visto, pero me gustaría experimentar
      En concreto, creo que se podría crear un backend que reciba AIR y genere un reporte de seguridad de memoria. Algo que identifique uso de valores indefinidos, escape de punteros de stack, uso después de liberar, doble liberación, alias xor mut, y cosas por el estilo
    • Estoy cayendo en la madriguera de URCL. Todavía no lo he mirado en profundidad, pero la línea temporal más divertida sería que una representación intermedia creada para Minecraft se convierta en un target de compilación práctico para varios lenguajes
  • Ya es un logro enorme, pero como dice el registro de desarrollo, todavía queda mucho más por delante. La idea de un compilador que durante la compilación solo modifique las partes necesarias del binario es fresca y a la vez completamente radical, y parece que ya está al alcance del proyecto Zig
    Me entusiasma lo que viene

  • Me emociona la parte que dice: “Un proyecto grande como el compilador Zig baja de 75 segundos a 20 segundos. Esto apenas empieza”. Me da curiosidad ver qué podrá hacer esta persona con esto; parece realmente brillante
    Me pregunto en qué estado está la gestión de paquetes. Intenté hacer una app con QuickJS + SDL3, pero por el caos del lado de C++ me fui a Rust, y ahí simplemente funcionó. Ojalá también pueda intentarlo en Zig

    • La gestión de paquetes de Zig es más manual que la de Rust. Consiste en traer la URL de un paquete con la CLI y luego importar el módulo desde el script de build
      También tiene ventajas: puedes depender de archivos arbitrarios, y muchos paquetes Zig que envuelven bibliotecas C se parecen más a scripts de build que dependen de releases en tarball sin modificar. Claro que para principiantes es un poco más difícil
      SDL3 tiene un wrapper nativo en Zig: https://github.com/Gota7/zig-sdl3
      También hay una versión más básica que reempaqueta la biblioteca/API C: https://github.com/castholm/SDL
      Para QuickJS, la API C es la única opción: https://github.com/allyourcodebase/quickjs-ng
      Zig hace muy fácil usar directamente paquetes C de esta forma, pero los tipos de Zig son mucho más estrictos, así que acabas haciendo bastantes conversiones de tipo al interactuar con la API
    • El compilador D dmd puede compilarse a sí mismo como build de debug
      real 0m18.444s, user 0m17.408s, sys 0m1.688s
      Incluso en un procesador muy viejo va así de rápido, así que no sentí necesidad de actualizar
      Son especificaciones como AMD Athlon(tm) 64 X2 Dual Core Processor 4400+, 2 núcleos, 2.3GHz, caché de 512KB
    • Me pregunto si hay alguna guía para hacer eso. Cuando compilé Zig, tardó bastante porque pasaba por varias etapas e incluía todo el proceso de bootstrap en wasm
    • Me sorprende que Zig pueda compilarse a sí mismo en 75 segundos. Incluso usando LLVM
  • Como dije también con D y Nature, para todo lenguaje que tenga su propio backend, tenemos la obligación de apoyar los proyectos que intentan no depender de LLVM
    Siento que LLVM estancó la investigación y desarrollo de compiladores, que demasiados lenguajes decidieron depender de LLVM, y que demasiada gente dejó de valorar los ciclos de iteración rápidos o dejó de esperar algo mejor
    La iteración rápida mediante compilación incremental y parcheo de binarios, junto con una buena depuración, debería ser una expectativa para los lenguajes nuevos, no una función de nicho ni algo tratado como demasiado difícil

    • Por otro lado, LLVM permitió que incluso lenguajes creados por individuos tuvieran de inmediato rendimiento competitivo y amplio soporte de plataformas, lo que hizo que proliferaran explosivamente. Zig es uno de ellos
      Toda la industria del renderizado en tiempo real está construida, en la práctica, sobre LLVM o forks de LLVM; Microsoft también cambió su compilador de shaders a LLVM y apenas ahora está empezando a subir el código upstream
      La mayor parte de la infraestructura de compiladores de consolas de videojuegos también está basada en Clang. Xbox ha seguido aferrándose a MSVC hasta ahora, pero es más bien una excepción
      En conjunto, LLVM ha sido un éxito enorme, especialmente para el bootstrap de cosas nuevas
    • Exacto. Una de las pocas cosas que veo positivas en Go es que está bootstrappeado y no depende de LLVM
  • No quiero sonar como si estuviera exigiendo algo o no lo agradeciera. Zig es un trabajo que se hace gratis. Pero lo que más me intriga es un cronograma realista para 1.0
    Zig coincide casi exactamente con lo que quería en un lenguaje de bajo nivel, y estoy esperando a que se estabilice
    Por supuesto, aprecio muchísimo la filosofía de diseño minimalista de Zig

    • Los proyectos serios como TigerBeetle fijan la versión, probablemente usando la última versión publicada. Veo las nightly más como algo experimental
  • El programa hello world creado con zig init pesa 9.3 MB al compilarse. Comparado con los 7.6 KB de -Doptimize=ReleaseSmall, es más de 1000 veces más grande, una barbaridad

    • Es una observación correcta. Otra observación es que el 82% de eso es información de depuración
      -OReleaseSmall -fno-strip genera un ejecutable de 580 KB, y -ODebug -fstrip genera un ejecutable de 1.4 MB
      El backend x86 de Zig ofrece una experiencia de depuración mucho mejor junto con un fork de lldb que entiende Zig: https://github.com/ziglang/zig/wiki/LLDB-for-Zig
      No recuerdo si ahora se puede ejecutar paso a paso la lógica de comptime. Fue un tema que se discutió recientemente
  • Creo que Julia debería considerar pasarse a Zig para obtener ganancias de rendimiento importantes. Recuerdo a los autores de Julia angustiándose cada vez que salía una versión de LLVM por miedo a regresiones de rendimiento

    • Julia está, en la práctica, fuertemente atado a LLVM. Gran parte del ecosistema depende de la existencia de LLVM por los intrinsics, la diferenciación automática (Enzyme) y la compilación para GPU. Ni hablar de Base y Core
      El compilador es bastante retargeteable, y esta también es un área en desarrollo activo. Así que en el futuro quizá se podría imaginar Zig como un compilador alternativo para algunas partes del lenguaje
    • ¿LLVM no se considera parte de la API pública de Julia? De hecho hay macros como @code_llvm que muestran el IR
    • Podría ser una forma de reducir los tiempos de compilación, pero creo que del lado de Julia todavía hay mucho por hacer
      Cosas como una caché de compilación más granular, mejores herramientas para evitar invalidaciones, eliminar la optimización de world splitting, aprovechar más el multithreading en el compilador, precompilación automática de firmas concretas y una generación de código más perezosa que haga hot-swap del código cuando ya esté compilado
    • Cada vez que aparece un nuevo backend de compilador se dice algo así. Soy bastante escéptico, pero si alguien lo toma como proyecto, sería interesante ver qué pasa
  • Desde la perspectiva de un principiante total, me da curiosidad saber en qué es mejor Zig que otros lenguajes. Lo entiendo como un C más moderno, pero ¿cuál es esa parte moderna?

    • Algunas cosas que se me ocurren: tiene un sistema de build integrado, sin usar varias herramientas y lenguajes separados y crípticos
      A diferencia de los arrays de C, Zig tiene slices que conocen su longitud, lo cual es mejor frente a desbordamientos de búfer, y los tipos opcionales explícitos se deben verificar obligatoriamente; no se permiten punteros nulos. Incluso cuando se permiten al integrarse con código C, el tipo lo deja claro
      También tiene enums, tagged unions y verificación exhaustiva obligatoria en expresiones switch
      El manejo de errores es explícito: las funciones devuelven errores (valores enum) que el llamador debe manejar de alguna forma. En C, aunque una función devuelva un entero que representa un error, se puede ignorar por completo
      Dicho eso, el lenguaje no trae integrada una forma estándar de devolver datos junto con errores. El patrón de pasar una estructura de error como parámetro se siente agregado a posteriori; creo que debería haber una sintaxis especial para eso
      Hay bloques defer y errdefer para hacer limpieza después de retornar de una función o de que ocurra un error, y en vez de macros se puede usar generación de código con comptime y reflexión de tipos como @typeInfo
      Al pasar asignadores a las bibliotecas, normalmente quien llama decide dónde y cómo asignar memoria, y solo con usar GeneralPurposeAllocator es más fácil encontrar fugas de memoria
      Después de empezar a programar seguí usando lenguajes de alto nivel, y odiaba las partes crípticas y contraintuitivas de C y su ecosistema alrededor; gracias a Zig, por primera vez empecé a disfrutar la programación de sistemas
  • ¿Esto solo reemplaza el backend? Me pregunto si todos los pases de análisis y tipos siguen ahí, o si también reduce la verificación
    Los ciclos rápidos de compilación ayudan a la productividad, pero creo que solo si también incluyen tests rápidos
    Entonces, ¿no sería más fácil simplemente interpretar y ejecutar Zig para depuración? Eso también resolvería el problema de repetir el trabajo para cada target

    • El punto central del modo debug es la capacidad de depurar, y no creo que sea trivial conectar un Zig interpretado a depuradores estándar como gdb o lldb, porque esas herramientas esperan un ejecutable con información de depuración DWARF
      Además, especialmente en áreas como desarrollo de videojuegos, el rendimiento en modo debug también es realmente muy importante
    • Lo único que se reemplazó es el backend. Los tests también deberían volverse más rápidos
      No hay una necesidad real de agregar un intérprete. Tener un backend personalizado significa que hoy se usa para debug, pero en un futuro mucho más lejano también podría competir con LLVM en velocidad
      Agregar un intérprete sirve de poco, porque de todos modos habría que escribir un backend personalizado
      El problema es que LLVM es lento tanto en debug como en release
  • ¿No es este uno de los prerrequisitos para volver a traer async/await a Zig?
    https://github.com/ziglang/zig/wiki/FAQ#what-is-the-status-o...

    • Esa parte ya la dejamos ordenada, y creo que podremos compartir una actualización interesante en los próximos 2 o 3 meses. Estamos rehaciendo I/O desde cero, y la mayor parte es trabajo de la biblioteca estándar
    • Si lees el enlace, parece que async no volverá, o al menos no antes de 2028