Files
zig/stage0
Motiejus Jakštys 0fc53ea8ea sema: add global seen-calls set for cross-function dead block dedup
Add a global seen_call_names/seen_call_nargs set to Sema that persists
across analyzeFuncBodyAndRecord calls (not reset per-function). This
matches upstream Zig's InternPool memoization which is global: when a
type-returning function (Int, Log2Int, etc.) is called in one function's
body and later in another function's body, upstream memoizes the result
and skips the dead block on the second call.

The set is checked at three points:
- Unresolved type function path (callee not found, known type name)
- Param type body scanning (generic param type resolution)
- Resolved type function path (returns_type handler)

After creating a dead block, the call is registered in the set so
subsequent calls with the same callee name and arg count skip it.

Also add two new sema unit tests:
- cross_fn_memoized_call.zig: two exports calling same inline helper
- nested_inline_dead_blocks.zig: nested comptime inline calls

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-02-24 20:10:26 +00:00
..
2026-02-20 12:33:48 +02:00
2026-02-18 22:49:36 +02:00
fmt
2026-02-20 10:30:47 +02:00
2026-02-17 10:56:11 +00:00
2026-02-24 10:10:14 +02:00
2026-02-14 00:03:26 +02:00

About

zig0 aspires to be an interpreter of zig 0.15.2 written in C.

This is written with help from LLM:

  • Lexer:
    • Datastructures 100% human.
    • Helper functions 100% human.
    • Lexing functions 50/50 human/bot.
  • Parser:
    • Datastructures 100% human.
    • Helper functions 50/50.
    • Parser functions 5/95 human/bot.
  • AstGen: TBD.

Testing

Quick test:

zig build fmt-zig0 test-zig0

Static analysis (takes a while, run separately):

zig build lint-zig0

More elaborate (tries all compilers + static analysis + ReleaseSafe):

zig build all-zig0 -Doptimize=ReleaseSafe

Most elaborate, takes >10m:

zig build all-zig0 -Doptimize=ReleaseSafe -Dvalgrind |& grep -v Warning

Debugging tips

Test runs infinitely? Build the test program executable:

$ zig build test-zig0 -Dzig0-no-exec

And then run it, capturing the stack trace:

gdb -batch \
    -ex "python import threading; threading.Timer(1.0, lambda: gdb.post_event(lambda: gdb.execute('interrupt'))).start()" \
    -ex run \
    -ex "bt full" \
    -ex quit \
    zig-out/bin/test

You are welcome to replace -ex "bt full" with anything other of interest.

Float handling

Float literals are parsed with strtold() (C11 standard, portable). On x86-64 Linux, long double is 80-bit extended precision (63 fraction bits).

When a float doesn't round-trip through f64, it's emitted as f128 (ZIR float128 instruction). The 80-bit extended value is converted to IEEE 754 binary128 encoding by bit manipulation — both formats share the same 15-bit exponent with bias 16383. The top 63 of binary128's 112 fraction bits come from the 80-bit value; the bottom 49 are zero-padded.

This means float128 literals lose ~49 bits of precision compared to the upstream Zig implementation (which uses native f128). This is acceptable because stage0 is a bootstrap tool — the real Zig compiler re-parses all source with full f128 precision in later stages. The test comparison mask in astgen_test.zig skips float128 payloads to account for this.

Previous approach used __float128/strtof128 (GCC/glibc extensions) for full precision, but these are not portable to TCC and other C11 compilers.