1 points par GN⁺ 2025-06-09 | 1 commentaires | Partager sur WhatsApp
  • Zig remplace, pour les cibles x86_64, le chemin par défaut où LLVM abaissait le bitcode en fichiers objet par son propre backend x86, ce qui réduit fortement le temps de compilation et l’usage mémoire des builds debug
  • Le backend x86 maison passe 1 987 behavior tests, soit davantage que les 1 980 du backend LLVM ; certains tests supplémentaires sur un total de 2 084 ne s’exécutent que dans les tests x86 self-hosted
  • Dans le benchmark hello.zig, la moyenne de 918 ms avec le chemin LLVM tombe à 275 ms avec le backend maison par défaut, soit une baisse de 70,1 % du wall time, tandis que le pic de RSS passe de 214 Mo à 137 Mo
  • Même sur de gros projets comme le compilateur Zig lui-même, le temps de build passe de 75 secondes à 20 secondes, mais Windows n’est pas encore concerné par le changement de valeur par défaut, car le linker COFF nécessite encore du travail
  • Les travaux restants portent sur la parallélisation complète de la génération de code, l’amélioration du linker, la stabilisation de l’incremental compilation, l’amélioration de la qualité du code x86 et l’extension du backend aarch64

Changement du backend par défaut pour x86_64

  • Pour les builds ciblant x86_64, Zig utilise désormais par défaut son propre backend x86
  • L’ancien chemin par défaut consistait pour LLVM à abaisser des fichiers de bitcode en fichiers objet
  • Sous Windows, la valeur par défaut n’a pas encore changé
    • Parce que le linker COFF nécessite encore du travail

État des behavior tests réussis

  • Le backend x86 maison passe 1 987 behavior tests
  • Le backend LLVM passe 1 980 behavior tests
  • Le total des behavior tests est de 2 084, mais les tests supplémentaires recoupent en grande partie les tests du backend x86 LLVM lui-même
    • Ces tests supplémentaires ne sont exécutés que lors des tests x86 self-hosted
  • En nombre de tests réussis, le backend x86 de Zig est donc plus avancé que le backend LLVM dans l’implémentation du langage Zig

Pourquoi concurrencer le chemin LLVM

  • La principale raison pour laquelle Zig concurrence LLVM sur la génération de code est qu’il peut créer un écart important en matière de vitesse de compilation
  • Le contexte associé est résumé dans l’explication sur Ziggit

Benchmark hello.zig

  • Résultat de zig build-exe hello.zig -fllvm :
    • Wall time moyen : 918 ms
    • Pic RSS : 214 Mo
    • Cycles CPU : 4,53 G
    • Instructions : 8,50 G
  • Résultat du chemin par défaut zig build-exe hello.zig :
    • Wall time moyen : 275 ms
    • Pic RSS : 137 Mo
    • Cycles CPU : 1,57 G
    • Instructions : 3,21 G
  • Le backend maison par défaut réduit plusieurs métriques par rapport au chemin LLVM
    • Wall time réduit de 70,1 %
    • Pic RSS réduit de 36,2 %
    • Cycles CPU réduits de 65,2 %
    • Instructions réduites de 62,2 %
    • Cache misses réduits de 86,1 %
    • Branch misses réduits de 78,3 %

Effets sur les grands projets

  • Sur de plus grands projets, comme le compilateur Zig lui-même, le temps de build passe de 75 secondes à 20 secondes
  • Le backend x86 maison peut fortement réduire les temps de compilation non seulement sur de petits exemples, mais aussi sur de grandes bases de code

Prochaines étapes

  • Zig a déjà commencé à travailler sur la parallélisation complète de la génération de code
  • Avec de nouvelles améliorations du linker et corrections de bugs, il sera possible de rendre l’incremental compilation stable et robuste avec ce backend
  • La qualité du code x86 généré peut encore être améliorée
  • La prochaine cible est aarch64, et le nouveau pass Legalize devrait accélérer le travail
  • Les builds les plus récents de la branche master peuvent être téléchargés depuis la page de téléchargement de Zig pour être testés directement

1 commentaires

 
GN⁺ 2025-06-09
Avis de Hacker News
  • D’après ce que je sais, Zig a beaucoup de chantiers en cours pour améliorer l’expérience de développement. Il y a quelque chose qui avance presque tous les jours, et il vient encore d’y avoir un truc comme https://github.com/ziglang/zig/pull/24124
    Il me semble qu’ils avaient aussi prévu le remplacement de code à chaud ; au rythme actuel de développement, ça ne m’étonnerait pas que ça fonctionne sur x86_64 d’ici un an
    Aujourd’hui, ma plus grosse douleur personnelle, c’est la vitesse de comptime. Le compilateur a beaucoup de travail à faire là-dessus, et faire tourner un DSL brainF** à la compilation est assez lent. Je l’ai essayé moi-même, c’était une expérience marrante
    Les nouveaux backends que Zig est en train d’introduire sont globalement très prometteurs. J’aimerais bien essayer d’écrire moi-même un backend URCL(https://github.com/ModPunchtree/URCL) pour Zig

    • Pour améliorer les performances de comptime, on sait ce qu’il faut faire, et une branche avait même été commencée il y a longtemps. Cela dit, il faut retravailler une bonne partie du code d’analyse sémantique ; c’est clairement faisable, nécessaire, et ça sera fait, mais c’est en concurrence avec d’autres priorités
    • Le remplacement de code à chaud serait énorme pour le développement de jeux. L’idée que Zig puisse pratiquement le prendre en charge par défaut avec un simple flag de compilation est impressionnante. J’aimerais bien voir quelqu’un essayer ça avec clang
    • Je me demande si la lenteur de comptime est vraiment un problème. Je construis une bibliothèque JSON-RPC et je m’appuie beaucoup sur comptime pour dispatcher les requêtes JSON vers des fonctions arbitraires
      À cause du typage statique strict, il n’y a pas moyen de faire à l’exécution un dispatch dynamique vers des fonctions ayant des paramètres arbitraires ; la seule méthode que j’ai trouvée consiste à déterminer à la compilation, avec comptime, le mapping des types de fonctions
      Comme chaque fonction arbitraire ajoute une copie de code passée par comptime, la taille du code risque d’augmenter
    • Je me demande s’il est facile de créer un backend personnalisé. Je n’ai pas encore regardé, mais j’aimerais expérimenter
      Plus précisément, j’imagine qu’on pourrait créer un backend qui prend l’AIR et produit un rapport de sûreté mémoire : identifier l’utilisation de valeurs indéfinies, les pointeurs de pile qui s’échappent, les use-after-free, les double free, les cas du type alias xor mut, etc.
    • Je suis en train de tomber dans le terrier du lapin à cause d’URCL. Je n’ai pas encore creusé en profondeur, mais la timeline la plus drôle serait qu’une représentation intermédiaire créée pour Minecraft devienne une cible de compilation pratique pour plusieurs langages
  • C’est déjà un énorme accomplissement, mais comme l’indique le journal de développement, il reste encore beaucoup à faire. L’idée d’un compilateur qui, pendant la compilation, ne modifie dans le binaire que les parties nécessaires est à la fois fraîche et complètement radicale, et elle semble désormais à portée du projet Zig
    J’ai hâte de voir la suite

  • Le passage « un gros projet comme le compilateur Zig passe de 75 secondes à 20 secondes. Et ce n’est que le début » me donne envie d’en voir plus. Je me demande ce que cette personne pourra en faire, elle a vraiment l’air brillante
    Je me demande où en est la gestion de paquets. J’avais essayé de faire une appli QuickJS + SDL3, mais je suis passé à Rust à cause du bazar côté C++, et là ça a juste marché. J’aimerais pouvoir tenter la même chose avec Zig

    • La gestion de paquets de Zig est plus manuelle que celle de Rust. On récupère l’URL du paquet via la CLI, puis on importe le module dans le script de build
      Cela a aussi des avantages : on peut dépendre d’archives arbitraires, et beaucoup de paquets Zig qui enveloppent des bibliothèques C ressemblent surtout à des scripts de build dépendant de releases tarball non modifiées. Bien sûr, c’est un peu plus difficile pour les débutants
      Il existe un wrapper Zig natif pour SDL3 : https://github.com/Gota7/zig-sdl3
      Il existe aussi un repackaging plus basique de la bibliothèque/API C : https://github.com/castholm/SDL
      Pour QuickJS, l’API C est la seule option : https://github.com/allyourcodebase/quickjs-ng
      Zig rend très facile l’utilisation directe de paquets C de cette manière, mais les types de Zig sont beaucoup plus stricts, donc on finit par faire beaucoup de casts lorsqu’on interagit avec l’API
    • Le compilateur D dmd peut se compiler lui-même en build debug
      real 0m18.444s, user 0m17.408s, sys 0m1.688s
      Même sur un très vieux processeur, il va assez vite pour que je n’aie pas vraiment eu besoin de mettre à niveau
      C’est quelque chose comme un AMD Athlon(tm) 64 X2 Dual Core Processor 4400+, 2 cœurs, 2,3 GHz, 512 Ko de cache
    • Je me demande s’il existe un guide pour faire ça. Quand j’ai compilé Zig, ça prenait longtemps parce qu’il fallait passer par plusieurs étapes, avec tout le processus de bootstrap depuis wasm
    • C’est impressionnant que Zig puisse se compiler lui-même en 75 secondes. Même en utilisant LLVM
  • Je l’ai déjà dit à propos de D et de Nature, mais pour tous les langages qui disposent de leur propre backend, nous avons le devoir de soutenir les projets qui cherchent à ne pas dépendre de LLVM
    LLVM a figé la R&D sur les compilateurs ; trop de langages ont choisi d’en dépendre, et trop de gens ont cessé de considérer des temps d’itération rapides comme quelque chose de précieux, ou ont cessé d’attendre mieux
    La compilation incrémentale, le patching de binaires pour itérer vite, et un bon débogage devraient faire partie des attentes envers les nouveaux langages, pas être traités comme des fonctionnalités de niche ou des choses trop difficiles

    • À l’inverse, LLVM a permis à des langages créés par des individus d’obtenir immédiatement des performances compétitives et une large prise en charge des plateformes, ce qui a provoqué une explosion de ces langages. Zig en fait partie
      Toute l’industrie du rendu temps réel repose pratiquement sur LLVM ou des forks de LLVM ; Microsoft a aussi remplacé son compilateur de shaders par LLVM et commence seulement maintenant à upstreamer son code
      La majeure partie de l’infrastructure de compilation des consoles de jeux est également basée sur Clang. Xbox reste jusqu’ici attachée à MSVC, mais c’est plutôt l’exception
      Dans l’ensemble, LLVM a été un immense succès, surtout pour le bootstrap de nouvelles choses
    • Exact. L’un des rares points que je vois positivement dans Go, c’est qu’il est bootstrapé et ne dépend pas de LLVM
  • Je ne veux pas donner l’impression d’exiger quoi que ce soit ni de manquer de gratitude. Zig est un travail fait gratuitement. Mais ce qui m’intéresse le plus, c’est un calendrier réaliste pour la 1.0
    Zig correspond presque exactement à ce que j’attendais d’un langage bas niveau, et j’attends qu’il se stabilise
    Bien sûr, j’apprécie vraiment la philosophie de conception minimaliste de Zig

    • Les projets sérieux comme TigerBeetle figent leur version, et utilisent probablement la dernière release. Je vois plutôt les nightly comme expérimentales
  • Un programme hello world créé avec zig init fait 9,3 Mo une fois compilé. Comparé aux 7,6 Ko avec -Doptimize=ReleaseSmall, c’est plus de 1000 fois plus gros, c’est énorme

    • C’est une observation juste. Une autre observation est que 82 % correspondent à des informations de débogage
      -OReleaseSmall -fno-strip produit un exécutable de 580 Ko, et -ODebug -fstrip produit un exécutable de 1,4 Mo
      Le backend x86 de Zig offre une bien meilleure expérience de débogage avec un fork de lldb qui comprend Zig : https://github.com/ziglang/zig/wiki/LLDB-for-Zig
      Je ne me souviens pas si l’on peut actuellement exécuter pas à pas la logique comptime. C’était un sujet discuté récemment
  • Julia devrait peut-être envisager de passer à Zig pour obtenir des gains de performance significatifs. Je me souviens que les auteurs de Julia s’inquiétaient nerveusement des régressions de performance à chaque release de LLVM

    • Julia est en réalité très fortement liée à LLVM. Une grande partie de l’écosystème dépend de la présence de LLVM, à cause des intrinsics, de la différentiation automatique (Enzyme) et de la compilation GPU. Sans même parler de Base et Core
      Le compilateur est assez largement reciblable, et c’est aussi un domaine en cours de développement actif. On pourrait donc peut-être imaginer, à l’avenir, Zig comme compilateur alternatif pour certaines parties du langage
    • LLVM n’est-il pas considéré comme faisant partie de l’API publique de Julia ? Il existe effectivement des macros comme @code_llvm qui affichent l’IR
    • Cela pourrait être une façon de réduire les temps de compilation, mais je pense qu’il reste encore beaucoup à faire côté Julia
      Par exemple des caches de compilation plus fins, de meilleurs outils pour éviter les invalidations, la suppression de l’optimisation de world splitting, une utilisation accrue du multithreading dans le compilateur, la précompilation automatique des signatures concrètes, et une génération de code plus paresseuse qui hot-swap le code une fois compilé
    • On entend ce discours à chaque nouveau backend de compilateur. Je suis assez sceptique, mais si quelqu’un prenait ça comme projet, il serait intéressant de voir ce qui se passerait
  • En tant que débutant complet, je me demande ce qui rend Zig meilleur que d’autres langages. Je le comprends comme un C plus moderne, mais quelle est cette partie moderne ?

    • Quelques éléments qui me viennent à l’esprit : un système de build intégré, au lieu d’utiliser plusieurs outils et langages séparés et obscurs
      Contrairement aux tableaux en C, Zig a des slices qui connaissent leur longueur, ce qui est meilleur vis-à-vis des dépassements de tampon ; les types optionnels explicites doivent obligatoirement être vérifiés, et les pointeurs nuls ne sont pas autorisés. Même lorsqu’ils le sont pour l’intégration avec du code C, le type l’indique clairement
      Il y a aussi les enum, les unions taguées et la vérification exhaustive imposée des expressions switch
      La gestion des erreurs est explicite : une fonction renvoie une erreur (une valeur d’enum) que l’appelant doit traiter d’une manière ou d’une autre. En C, même si une fonction renvoie un entier pour indiquer une erreur, on peut l’ignorer complètement
      En revanche, il n’y a pas de manière standard intégrée au langage pour renvoyer des données avec une erreur. Le pattern consistant à passer une structure d’erreur en paramètre donne l’impression d’avoir été greffé, et je pense qu’il faudrait une syntaxe spéciale pour cela
      Il existe des blocs defer et errdefer pour le nettoyage après un retour de fonction ou une erreur, et au lieu de macros on peut utiliser la génération de code comptime et la réflexion de type comme @typeInfo
      En passant des allocateurs aux bibliothèques, l’appelant décide généralement où et comment allouer la mémoire, et rien qu’avec GeneralPurposeAllocator, il est facile de trouver les fuites mémoire
      Depuis que j’ai commencé à programmer, j’ai toujours utilisé des langages de haut niveau et je détestais les aspects obscurs et contre-intuitifs de C et de son écosystème ; Zig m’a donné envie, pour la première fois, de faire de la programmation système avec plaisir
  • Est-ce seulement le backend qui a été remplacé ? Je me demande si toutes les passes d’analyse et de typage restent présentes, ou si la validation est elle aussi réduite
    Les cycles de compilation rapides aident la productivité, mais seulement s’ils incluent aussi des tests rapides
    Dans ce cas, ne serait-il pas plus simple d’exécuter Zig en mode interprété pour le debug ? Cela résoudrait aussi le problème de devoir refaire le travail pour chaque cible

    • L’enjeu central du mode debug est la capacité à déboguer, et connecter du Zig interprété à un débogueur standard comme gdb ou lldb ne me semble pas trivial. Ces outils s’attendent à un exécutable avec des informations de débogage DWARF
      J’ajouterais que, notamment dans des domaines comme le développement de jeux, les performances en mode debug comptent vraiment beaucoup
    • Seul le backend a été remplacé. Les tests devraient aussi devenir plus rapides
      Il n’y a pas de réel besoin d’ajouter un interpréteur. Avoir un backend personnalisé signifie qu’il sert aujourd’hui au debug, mais qu’à bien plus long terme il pourrait aussi rivaliser avec LLVM en vitesse
      Ajouter un interpréteur serait peu utile, puisqu’il faudrait de toute façon écrire un backend personnalisé
      Le problème est que LLVM est lent, aussi bien en debug qu’en release
  • N’est-ce pas l’un des prérequis pour ramener async/await dans Zig ?
    https://github.com/ziglang/zig/wiki/FAQ#what-is-the-status-o...

    • Cette partie est entièrement clarifiée, et je pense pouvoir partager des mises à jour intéressantes dans les 2 ou 3 prochains mois. Nous reconstruisons l’I/O depuis la base, et l’essentiel du travail concerne la bibliothèque standard
    • À lire le lien, on dirait qu’async ne reviendra pas, ou du moins pas avant 2028