Add three pieces of support needed for compiler_rt corpus files that
use @export to make functions visible:
- ZIR_INST_EXPORT handler in analyzeBodyInner: when processing a
comptime block containing @export, extract the target declaration
name from the ZIR_INST_DECL_REF/DECL_VAL instruction and record it
for later use by zirFunc.
- ZIR_INST_FUNC_FANCY payload parsing in zirFunc: functions with
explicit calling conventions (callconv(.c)) use func_fancy instead
of func/func_inferred. Parse the different extra layout
{param_block, body_len, bits} with optional trailing cc, ret_ty,
and noalias fields.
- Export-aware function filtering: zirFunc now checks both the
declaration-level export flag and the @export-collected names list
when deciding whether to analyze a function body.
The exported compiler_rt functions are now found and analyzed, but
their bodies produce fewer AIR instructions than Zig because the C
sema does not yet implement imports, field access, or function calls.
Corpus test comments updated to reflect new status.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
With .cache_mode = .whole, comp.update() returns immediately on a
cache hit, skipping sema entirely. The verbose_air_callback never
fires, so the collector returns 0 functions. This causes spurious
test passes when the C sema also returns 0 functions (e.g. for
unported @export), because 0 == 0 looks like a match.
Switch to .incremental so that sema always runs and the callback
always fires, making test results deterministic across runs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port getParamBody (from Zir.zig) and parameter processing in zirFunc
(from PerThread.zig analyzeFnBodyInner) to handle function parameters.
For each param, resolves the type from the param's type body and emits
AIR_INST_ARG instructions mapped to the param ZIR instructions.
Also adds explicit handling for ZIR_INST_PARAM (mapped to void at
module level) and ZIR_INST_RESTORE_ERR_RET_INDEX_FN_ENTRY (no-op in
ReleaseFast) in analyzeBodyInner.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move padding awareness from collection (verbose_air.zig) to the test
comparison (sema_test.zig). Air.Inst.Data is an 8-byte union where
some variants (un_op, no_op, ty, repeat) use fewer bytes; the rest is
uninitialised padding. Instead of zeroing padding at collection time,
compare only the meaningful bytes per tag in the test harness.
This reverts the verbose_air.zig zeroing from fbfecf51da and
replaces the bulk std.mem.eql in airCompareOne with a per-instruction
loop that also gives better diagnostics on mismatch (instruction
index, tag, byte count).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three issues fixed to enable the "return integer" test
(export fn f() u32 { return 42; }):
1. AIR tag storage: AirInstTag was a C enum (4 bytes) but the Zig-side
CAir expects u8 (matching Air.Inst.Tag = enum(u8)). The byte-for-byte
comparison read padding bytes instead of subsequent tags. Fixed by
storing tags as uint8_t in Air and Sema structs.
2. New ZIR_INST_RET_NODE handler: resolves the operand, coerces from
comptime_int to the function return type via coerceIntRef, and emits
AIR_INST_RET.
3. Return type resolution in zirFunc: reads the actual return type from
ZIR extra data (ret_ty_body_len == 1) instead of hardcoding void.
Also rewrites the AIR datas comparison to be tag-aware with canonical
ref renumbering, so structurally equivalent AIR compares equal even
when InternPool indices differ between C and Zig.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Air.Inst.Data is a union; variants smaller than 8 bytes (un_op,
no_op, ty, repeat) leave padding bytes uninitialised. Zero the
destination buffer and copy only the meaningful bytes per instruction
so that byte-level comparisons in tests are deterministic and
valgrind-clean.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the heap-allocated error_msg with a fixed-size caller-provided
buffer, making error reporting infallible. All error paths now write
into the buffer via bufPrint with truncation on overflow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Port zirFunc to C sema so that `export fn f() void {}` produces
matching AIR on both the C and Zig sides. Configure verbose_air.zig
to use the self-hosted wasm backend (use_llvm=false) with ReleaseFast,
which eliminates error tracing and safety-check instructions.
Enable the "sema air: empty void function" test case.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
With emit_bin=false, the compiler never queued functions for analysis,
making the verbose_air_callback a no-op — all corpus files produced 0
AIR functions on both C and Zig sides, so Stage 3 comparison was
vacuous.
Set emit_bin=true so that `export fn` and `@export` trigger function
analysis. Disable 5 compiler_rt corpus files that now expose the
Zig-vs-C mismatch (they use @export but C sema doesn't port zirFunc
yet). Add 3 skipped export-fn test tiers in sema_test.zig as targets
for incremental zirFunc porting.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use allocatedSlice() instead of .items to get the full [0..capacity]
slice for realloc. .items only covers [0..len] which causes an
out-of-bounds access when capacity > len.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
src/verbose_air.zig now only collects Air data (zig_compile_air) instead
of comparing it (zig_compare_air). The comparison logic lives in
stage0/sema_test.zig, keeping testing infrastructure in stage0/.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Hardcoding the module root to dirname(src_path) caused "import of file
outside module path" for any @import("../...") in corpus files. Add an
optional module_root parameter so stages_test can symlink to the repo
root, allowing all relative imports to resolve within the module path.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The git-describe version string (including commit hash) was passed via
exe_options to zig_internals_mod, causing verbose_dumper to recompile
(~7 min) after every commit. Create separate zig0_exe_options with a
fixed version "0.15.2-zig0-dev" for test-zig0/all-zig0 targets.
Also verify matched_count against c_func_count in Air comparisons to
catch spurious extra functions from the C pipeline.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Changing src/ files invalidates the verbose_dumper cache, triggering a
~7 minute recompilation. Document this in both orchestrator and worker
prompts, with the alternative of using --verbose-air.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of writing file content to /tmp (which broke relative imports
like codecs/asn1.zig), symlink the original file's directory into
.zig-cache/tmp/zig0_test. This keeps the module root outside lib/std/
(avoiding module path conflicts) while preserving subdirectory import
resolution through the symlink.
In verbose_air.zig, use Compilation.Path.fromUnresolved to construct the
module root so it gets the same canonical root enum (.local_cache, etc.)
as file paths computed during import resolution, avoiding isNested
root mismatches.
Fixes the codecs.zig test failure (434/434 tests now pass).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Both zig_dump_intern_pool and c_dump_intern_pool were unimplemented stubs
with no callers. InternPool correctness is validated by unit tests and Air
comparison.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pass C-side SemaFuncAir arrays into zig_compare_air so the callback
can compare Air tags/datas/extra directly against the Zig compiler's
in-memory arrays, eliminating 4 heap allocations + 3 memcpys per
function.
Fix the early-return guard in PerThread.zig to also check
verbose_air_callback, so the callback fires even when
enable_debug_extensions is false (ReleaseFast).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Export raw Air arrays (tags, datas, extra) from the Zig compiler via a
RawAirCallback on Compilation, and memcmp them against C-produced arrays
instead of comparing formatted text output. This is more robust (catches
any byte-level divergence) and eliminates the need for the C-side text
formatter.
- Add RawAirCallback type and field to Compilation
- Rewrite src/verbose_air.zig: raw array export instead of text capture
- Update stage0 tests to use compareAir with expectEqualSlices
- Delete stage0/verbose_air.{c,h} (no longer needed)
- Remove verbose_air.c/h from build.zig file lists
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove all @import("zig_internals") from stage0/ so that test_obj
compilation is independent of the Zig compiler (~6min). The sema
comparison now uses text-based dumpers:
- Zig side (src/verbose_air.zig): compiles source through the full Zig
pipeline, captures verbose_air output, exports zig_dump_air() as a C
function. Compiled as a separate dumper_obj that is cached
independently.
- C side (stage0/verbose_air.c): formats C Air structs to text in the
same format as Zig's Air/print.zig.
Changing stage0 code no longer triggers Zig compiler recompilation:
C compile + cached test_obj + cached dumper + link = seconds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the count-only check with a faithful textual comparison,
analogous to how expectEqualZir compares AstGen output:
- Export Zcu from test_exports so tests can construct a PerThread
- Parse Zig verbose_air output into per-function sections keyed by FQN
- For each C function Air, render it as text via air.write() using
the Zig PerThread (InternPool indices must match between C and Zig
for the same source), then compare against the Zig reference text
For the current corpus (codecs.zig, no functions), both sides produce
zero entries so the comparison loop is empty. When zirFunc is ported
and a corpus file with functions is added, this will exercise real
per-function Air matching.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Parse the captured Zig verbose_air output to count per-function Air
sections and verify that C sema produces the same number. For the
current corpus (codecs.zig, no functions), both sides produce zero
entries. When zirFunc is ported and functions appear, per-function
textual Air comparison will be added.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enable verbose_air in the Zig Compilation and use a Writer.Allocating
to capture per-function Air text for later comparison with C sema output.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Change semaAnalyze to return SemaFuncAirList (a list of per-function Air
structs) instead of a single flat Air. This mirrors the Zig compiler's
per-function Air architecture. Currently returns an empty list since
zirFunc is not yet ported; module-level Air arrays are freed directly.
Update sema_c.zig, sema_test.zig, stages_test.zig, and zig0.c to use
the new types. Remove expectEqualAir (replaced by textual comparison
in a subsequent commit).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The zig test step previously compiled Zig code and linked C objects in
a single invocation. Since the Zig compiler hashes all link inputs
(including .o file content) into one cache key, changing -Dzig0-cc or
editing any C file invalidated the 6-minute Zig compilation cache.
Split into two steps: emit the Zig test code as an object (cached
independently of C objects), then link it with the C objects in a
separate executable step. Manually set up the test runner IPC protocol
via enableTestRunnerMode() to preserve build summary integration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a verbose_air_output field to Compilation that redirects verbose Air
dumps to a caller-provided writer instead of stderr. When set, liveness
is omitted from the output to support textual comparison in stage0 tests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use Directories.init() to resolve ~/.cache/zig (global) and
.zig-cache (local) instead of a temp dir, re-using the same
resolution logic as src/main.zig (introspect module).
- Point zig_lib at zig-out/lib/zig/ (installed copy) instead of lib/
(source tree) to avoid "file exists in modules 'root' and 'std'"
when compiling files that live under lib/.
- Heap-allocate the thread pool to keep its address stable. Worker
threads reference the Pool's condvar/mutex; a by-value copy into
ZigSemaResult left them waiting on the original stack address while
deinit broadcast on the copy, causing a deadlock.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add zigSema helper (stage0/sema.zig) that creates a Compilation,
points it at a source file, and runs the full Zig sema pipeline.
Export Compilation and Package from test_exports.zig. Wire up in
stagesCheck to run Zig sema alongside C sema.
Not yet working: files under lib/ conflict with the auto-created
std module ("file exists in modules 'root' and 'std'"). The fix
(using .root = .none with absolute path) needs testing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add expectEqualAir() that validates the converted Zig Air matches
the original C Air (instruction count, tags, and extra data). Use it
in stagesCheck to verify the conversion is faithful for all corpus
files processed through the sema stage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract cSema(gpa, c_zir) as a reusable function that runs the full
C sema pipeline (init IP → init sema → analyze → convert to Zig Air)
and returns a SemaResult owning all resources. Update all sema tests
in sema_test.zig and stages_test.zig to use it, removing duplicated
pipeline setup code.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add stage0/sema_c.zig that converts C Sema output (Air struct) to Zig's
Air type via MultiArrayList, with per-tag data dispatch. Update
stagesCheck to use the conversion, and extend the const x = 42 test to
verify both Air structure and InternPool contents.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add enough C sema handling so that `const x = 42;` interns the integer
value 42 in the InternPool, matching the Zig reference implementation.
- Add Declaration.Flags.Id helper functions (hasName, hasLibName,
hasTypeBody, hasValueBody, hasSpecialBodies) ported from Zir.zig
- Add zirInt handler to intern comptime integer values
- Add zirStructDecl handler to parse struct_decl extra payload,
iterate declarations, and analyze their value bodies
- Add cross-check test comparing C and Zig InternPool entries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Wire src/test_exports.zig through build.zig so zig0 tests can import
the real Zig InternPool. Add a test that initializes both the C and Zig
InternPools and compares all 124 pre-interned entries index by index.
Also add rule to skill file: never run `zig build test` or bare
`zig build` (they test upstream Zig and take ages).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Combine two specialized skills (port-astgen for astgen_test.zig,
fix-stages for stages_test.zig) into a single parameterized skill
that takes any test file as input. Improvements over the originals:
- Config table maps test files to modifiable/reference files
- Flush accumulated passing tests before dispatching worker
- Fast test-zig0 for per-iteration verification, valgrind only in final check
- Worker budget (~15 cycles) to avoid context exhaustion
- Guard rail: skip test after 2 consecutive no-progress
- Worker truncates output (tail -50) and never reads whole reference files
- Handles all failure types: parser, AstGen, and sema
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add core Sema analysis infrastructure:
- InstMap operations: ensureSpaceForBody, get, put
- resolveInst: maps ZIR refs to AIR refs (pre-interned + inst_map)
- addAirInst: appends AIR instructions with auto-growth
- SemaBlock helpers: init, deinit, blockAddInst
- zirDbgStmt handler with comptime elision and coalescing
Implement analyzeBodyInner dispatch loop handling:
- dbg_stmt, break_inline, ret_implicit, extended (stub),
block_inline (recursive body analysis), declaration (skip)
- Default case maps unhandled instructions to void_type
Update semaAnalyze to set up root block, verify ZIR instruction 0
is struct_decl, exercise dispatch infrastructure, and transfer AIR
array ownership to returned Air struct.
Add smoke test for "fn foo() void {}" declarations.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Create sema_test.zig with:
- InternPool unit tests: pre-interned types/values, ipTypeOf,
ipIntern deduplication, new key interning, vector/pointer types
- Sema smoke tests: empty source and "const x = 0;" through
full C pipeline (parse → astgen → sema) without crashing
Wire sema_test.zig into test_all.zig.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>