1 pontos por GN⁺ 2025-06-09 | 1 comentários | Compartilhar no WhatsApp
  • O Zig mudou o caminho padrão em destinos x86_64, no qual o LLVM rebaixava bitcode para arquivos objeto, para seu backend x86 próprio, reduzindo significativamente a velocidade de compilação e o uso de memória em builds de depuração
  • O backend x86 próprio passa em 1.987 behavior tests, mais do que os 1.980 do backend LLVM; do total de 2.084, alguns testes adicionais são executados apenas nos testes x86 self-hosted
  • No benchmark hello.zig, a média de 918 ms do caminho LLVM caiu para 275 ms com o backend próprio padrão, reduzindo o wall time em 70,1%, e o pico de RSS também caiu de 214 MB para 137 MB
  • Mesmo em projetos grandes como o próprio compilador Zig, o tempo de build caiu de 75 segundos para 20 segundos, mas o Windows ainda não está incluído na mudança de padrão porque o linker COFF precisa de mais trabalho
  • O trabalho restante segue com paralelização completa da geração de código, melhorias no linker, estabilização da compilação incremental, melhoria da qualidade do código x86 e expansão do backend aarch64

Mudança do backend padrão para x86_64

  • Em builds para destinos x86_64, o Zig agora usa por padrão seu backend x86 próprio
  • O caminho padrão anterior era o LLVM rebaixar arquivos de bitcode para arquivos objeto
  • No Windows, o padrão ainda não foi alterado
    • Porque ainda é necessário mais trabalho no linker COFF

Status de aprovação nos behavior tests

  • O backend x86 próprio passa em 1.987 behavior tests
  • O backend LLVM passa em 1.980 behavior tests
  • O total de behavior tests é 2.084, mas os testes adicionais em geral se sobrepõem aos testes do backend x86 próprio do LLVM
    • Esses testes adicionais são executados apenas durante os testes x86 self-hosted
  • Pelo número de aprovações, o backend x86 do Zig está em um estado mais avançado do que o backend LLVM na implementação da linguagem Zig

Por que competir com o caminho LLVM

  • O principal motivo para o Zig competir com o LLVM na geração de código é que isso pode gerar uma grande diferença na velocidade de compilação
  • O contexto relacionado está resumido na explicação no Ziggit

Benchmark hello.zig

  • Resultado de zig build-exe hello.zig -fllvm:
    • Wall time médio: 918 ms
    • Pico de RSS: 214 MB
    • Ciclos de CPU: 4,53 G
    • Instruções: 8,50 G
  • Resultado do caminho padrão zig build-exe hello.zig:
    • Wall time médio: 275 ms
    • Pico de RSS: 137 MB
    • Ciclos de CPU: 1,57 G
    • Instruções: 3,21 G
  • O backend próprio padrão reduz vários indicadores em relação ao caminho LLVM
    • Wall time 70,1% menor
    • Pico de RSS 36,2% menor
    • Ciclos de CPU 65,2% menores
    • Instruções 62,2% menores
    • Cache misses 86,1% menores
    • Branch misses 78,3% menores

Efeito em projetos grandes

  • Em projetos maiores, como o próprio compilador Zig, o tempo de build caiu de 75 segundos para 20 segundos
  • O backend x86 próprio pode reduzir significativamente o tempo de compilação não só em exemplos pequenos, mas também em bases de código grandes

Próximos trabalhos

  • O Zig já iniciou o trabalho de paralelização completa da geração de código
  • Com mais melhorias no linker e correções de bugs, será possível tornar a compilação incremental estável e robusta junto com este backend
  • Ainda há espaço para melhorar a qualidade do código x86 gerado
  • O próximo alvo é aarch64, e espera-se que o trabalho seja acelerado graças ao novo Legalize pass
  • Builds recentes do branch master podem ser baixados na página de downloads do Zig para testes diretos

1 comentários

 
GN⁺ 2025-06-09
Comentários do Hacker News
  • Pelo que sei, Zig tem muito trabalho em andamento para oferecer uma experiência de desenvolvimento melhor. Quase todo dia há algo sendo trabalhado, e agora mesmo apareceu algo como https://github.com/ziglang/zig/pull/24124
    Pelo que lembro, antes também havia planos para hot code replacement; no ritmo atual de desenvolvimento, eu não ficaria surpreso se isso funcionasse em x86_64 dentro de um ano
    Hoje, minha maior dor pessoal é a velocidade do comptime. O compilador tem muito a fazer aqui, e rodar uma DSL brainF** em tempo de compilação é bem lento. Eu mesmo testei, e foi um experimento engraçado
    Os novos backends que o Zig está introduzindo, no geral, me deixam muito animado. Tenho vontade de criar eu mesmo um backend URCL(https://github.com/ModPunchtree/URCL) para Zig

    • Quanto a melhorar o desempenho do comptime, já se sabe o que precisa ser feito, e há muito tempo eu até comecei a trabalhar em uma branch. Só que isso exige retrabalhar bastante o código de análise semântica; é algo que claramente pode, deve e vai ser feito, mas está competindo com outras prioridades
    • Hot code replacement seria enorme para desenvolvimento de jogos. A ideia de o Zig acabar oferecendo isso de forma nativa basicamente com uma flag do compilador é incrível. Quero ver fazerem isso com clang
    • Fico me perguntando se o fato de comptime ser lento é realmente um problema. Estou criando uma biblioteca JSON-RPC e dependo bastante de comptime para despachar requisições JSON para funções arbitrárias
      Por causa da tipagem estática rígida, não há como fazer despacho dinâmico em runtime para funções com parâmetros arbitrários; o único jeito que encontrei foi descobrir, em tempo de compilação, o mapeamento dos tipos das funções usando comptime
      Acho que o tamanho do código vai crescer, porque haverá uma cópia de código gerada por comptime para cada função arbitrária
    • Fico curioso para saber se é fácil criar um backend customizado. Ainda não olhei, mas gostaria de experimentar
      Especificamente, acho que daria para criar um backend que recebe AIR e gera um relatório de segurança de memória. Algo que identifique uso de valores indefinidos, escape de ponteiros de stack, use-after-free, double free, alias xor mut e coisas do tipo
    • Estou caindo na toca do coelho por causa do URCL. Ainda não olhei a fundo, mas a linha do tempo mais engraçada seria uma representação intermediária criada para Minecraft virar um alvo de compilação prático para várias linguagens
  • Já é uma conquista enorme, mas, como está escrito no log de desenvolvimento, ainda há muito mais por vir. A ideia de um compilador que, durante a compilação, modifica apenas as partes necessárias do binário é ao mesmo tempo nova e completamente radical, e agora parece estar ao alcance do projeto Zig
    Estou animado pelo que vem pela frente

  • A parte “um projeto grande como o compilador Zig cai de 75 segundos para 20 segundos. Isso é só o começo” me deixa animado. Fico curioso para ver o que essa pessoa consegue fazer com isso; ela parece realmente inteligente
    Fico me perguntando em que estado está o gerenciamento de pacotes. Tentei criar um app QuickJS + SDL3, mas acabei indo para Rust por causa da confusão no lado C++, e lá simplesmente funcionou bem. Seria bom se desse para tentar também em Zig

    • O gerenciamento de pacotes do Zig é mais manual que o do Rust. Você traz a URL do pacote pela CLI e depois importa o módulo no script de build
      Isso também tem vantagens: dá para depender de arquivos arbitrários, e muitos pacotes Zig que encapsulam bibliotecas C são praticamente scripts de build que dependem de releases em tarball não modificados. Claro, para iniciantes é um pouco mais complicado
      Há um wrapper nativo em Zig para SDL3: https://github.com/Gota7/zig-sdl3
      Também há um reempacotamento mais básico da biblioteca/API C: https://github.com/castholm/SDL
      Para QuickJS, a API C é a única opção: https://github.com/allyourcodebase/quickjs-ng
      O Zig torna bem fácil usar pacotes C diretamente desse jeito, mas os tipos do Zig são muito mais rígidos, então você acaba fazendo bastante casting ao interagir com a API
    • O compilador D dmd consegue compilar a si mesmo em build de debug
      real 0m18.444s, user 0m17.408s, sys 0m1.688s
      Mesmo em um processador bem antigo fica nesse nível, então, por ser rápido demais, acabei nem fazendo upgrade
      É algo como AMD Athlon(tm) 64 X2 Dual Core Processor 4400+, 2 núcleos, 2,3 GHz, cache de 512 KB
    • Fico curioso se existe um guia para fazer isso. Quando compilei o Zig, levou bastante tempo por passar por várias etapas, incluindo todo o processo de bootstrap em wasm
    • É impressionante que o Zig consiga compilar a si mesmo em 75 segundos. Mesmo usando LLVM
  • Como já disse sobre D e Nature, para toda linguagem que tem backend próprio, nós temos a obrigação de apoiar projetos que tentam não depender do LLVM
    Parece que o LLVM estagnou a pesquisa e o desenvolvimento de compiladores, que linguagens demais decidiram depender dele, e que gente demais deixou de valorizar tempos rápidos de iteração ou de esperar algo melhor
    Iterar rapidamente com compilação incremental e patching de binários, além de ter boa depuração, deveria ser a expectativa para novas linguagens, não algo tratado como recurso de nicho ou como difícil demais

    • Por outro lado, o LLVM permitiu que até linguagens criadas por indivíduos já nascessem com desempenho competitivo e amplo suporte a plataformas, fazendo isso explodir. O Zig é uma delas
      A indústria inteira de renderização em tempo real é, na prática, construída sobre LLVM ou forks de LLVM; a Microsoft também trocou seu compilador de shaders para LLVM e só agora começou a upstreamar o código
      A maior parte da infraestrutura de compiladores de consoles de jogos também é baseada em Clang. O Xbox ainda insiste no MSVC até hoje, mas é quase uma exceção
      No geral, o LLVM teve um sucesso enorme, especialmente no bootstrap de coisas novas
    • Concordo. Uma das poucas coisas que vejo positivamente no Go é que ele é bootstrapped e não depende do LLVM
  • Não quero soar exigente nem ingrato. Zig é um trabalho feito de graça. Mas o que mais me intriga é um cronograma realista para a 1.0
    Zig corresponde quase exatamente ao que eu queria em uma linguagem de baixo nível, e estou esperando que ela se estabilize
    Claro, sou realmente grato pela filosofia de design minimalista do Zig

    • Projetos sérios como o TigerBeetle fixam a versão e provavelmente usam o release mais recente. Vejo as nightlies mais como experimentais
  • Um programa hello world criado com zig init fica com 9,3 MB ao compilar. Comparado aos 7,6 KB de -Doptimize=ReleaseSmall, é mais de 1000 vezes maior, o que é enorme

    • A observação está correta. Outra observação é que 82% disso são informações de depuração
      -OReleaseSmall -fno-strip gera um executável de 580 KB, e -ODebug -fstrip gera um executável de 1,4 MB
      O backend x86 do Zig oferece uma experiência de depuração muito melhor junto com um fork do lldb que entende Zig: https://github.com/ziglang/zig/wiki/LLDB-for-Zig
      Não lembro se hoje dá para executar passo a passo a lógica de comptime. Foi um tema discutido recentemente
  • Acho que Julia deveria considerar migrar para Zig para obter ganhos consideráveis de desempenho. Lembro dos autores de Julia ficando ansiosos, preocupados com regressões de desempenho a cada release do LLVM

    • Julia é, na prática, fortemente acoplada ao LLVM. Grande parte do ecossistema depende da existência do LLVM por causa de intrinsics, diferenciação automática (Enzyme) e compilação para GPU. Sem falar em Base e Core
      O compilador é bastante retargetable, e essa também é uma área em andamento ativo. Então talvez no futuro dê para imaginar Zig como um compilador alternativo para alguns pedaços da linguagem
    • LLVM não é considerado parte da API pública de Julia? De fato, há macros como @code_llvm que mostram o IR
    • Pode ser uma forma de reduzir o tempo de compilação, mas acho que ainda há muito a fazer do lado de Julia
      Coisas como um cache de compilação mais granular, ferramentas melhores para evitar invalidação, remoção da otimização de world splitting, maior uso de multithreading no compilador, pré-compilação automática de assinaturas concretas e geração de código mais preguiçosa que faça hot-swap do código quando ele for compilado
    • Esse tipo de comentário aparece toda vez que surge um novo backend de compilador. Sou bem cético, mas, se alguém assumisse isso como projeto, seria interessante ver o que aconteceria
  • Do ponto de vista de um completo iniciante, fico curioso sobre em que Zig é melhor que outras linguagens. Entendo que seja um C mais moderno, mas qual é a parte moderna?

    • Só para listar algumas coisas que me vêm à cabeça: há um sistema de build integrado, sem precisar de várias ferramentas e linguagens separadas e obscuras
      Ao contrário dos arrays de C, Zig tem slices que conhecem seu comprimento, o que é melhor em relação a estouros de buffer; tipos opcionais explícitos precisam obrigatoriamente ser verificados; e ponteiros nulos não são permitidos. Mesmo quando são permitidos ao integrar com código C, o tipo deixa isso claro
      Também há enums, tagged unions e verificação exaustiva obrigatória em expressões switch
      O tratamento de erros é explícito, e funções retornam erros (valores de enum) que o chamador precisa tratar de alguma forma. Em C, mesmo que uma função retorne um inteiro indicando erro, ele pode ser completamente ignorado
      Por outro lado, não há uma forma padrão embutida na linguagem para retornar dados junto com erros. O padrão de passar uma struct de erro como parâmetro parece algo acrescentado, e acho que deveria haver uma sintaxe especial para isso
      Há blocos defer e errdefer para limpeza depois de retorno de função ou ocorrência de erro, e, em vez de macros, é possível usar geração de código com comptime e reflexão de tipos como @typeInfo
      Ao passar alocadores para bibliotecas, quem chama normalmente decide onde e como a memória será alocada, e só de usar GeneralPurposeAllocator já fica mais fácil encontrar vazamentos de memória
      Desde que comecei a programar, usei linguagens de alto nível o tempo todo e detestava os pontos obscuros e contraintuitivos de C e do ecossistema ao redor; com Zig, pela primeira vez passei a gostar de programação de sistemas
  • Isso foi só uma troca de backend? Fico curioso se todas as passagens de análise e tipos ainda permanecem, ou se a validação também é reduzida
    Ciclos rápidos de compilação ajudam a produtividade, mas acho que só quando também incluem testes rápidos
    Nesse caso, não seria mais fácil simplesmente executar Zig interpretado para debug? Isso também resolveria o problema de ter que repetir o trabalho para cada alvo

    • O ponto central do modo debug é a capacidade de depuração, e conectar Zig interpretado a depuradores padrão como gdb ou lldb não parece algo trivial. Essas ferramentas esperam um executável com informações de debug DWARF
      Além disso, especialmente em áreas como desenvolvimento de jogos, o desempenho em modo debug também é realmente muito importante
    • Só o backend foi substituído. Os testes também devem ficar mais rápidos
      Não há necessidade prática de adicionar um interpretador. Ter um backend customizado significa que, embora ele seja usado para debug agora, em um futuro bem mais distante ele também poderá competir com LLVM em velocidade
      Mesmo adicionando um interpretador, ainda assim seria preciso escrever um backend customizado, então teria pouca utilidade
      O problema é que o LLVM é lento tanto em debug quanto em release
  • Isso não é um dos pré-requisitos para trazer async/await de volta ao Zig?
    https://github.com/ziglang/zig/wiki/FAQ#what-is-the-status-o...

    • Essa parte já foi toda organizada, e acho que poderemos compartilhar uma atualização interessante nos próximos 2 ou 3 meses. Estamos refazendo I/O do zero, e a maior parte é trabalho na biblioteca padrão
    • Lendo o link, parece que async não vai voltar, ou pelo menos não até 2028