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>
Split cppcheck into per-file checks (warning,style,performance,portability)
and a combined unusedFunction check across all C files. Remove dead code
(addExtraU32, rvalueDiscard, wipMembersNextDecl, wipMembersBodiesAppend,
findNextContainerMember, NodeContainerField). Wire up zig0Run to actually
call astParse/astGen and print stats, eliminating unusedFunction warnings
for the public API.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace parser's fail() and astgen's flag-only SET_ERROR(ag) with a
single SET_ERROR(ctx, msg) macro in common.h that stores the error
message in ctx->err_buf and sets ctx->has_compile_errors. Both Parser
and AstGenCtx now carry the same err_buf[ERR_BUF_SIZE] field.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add warn() for non-fatal parse errors (like Zig's Parse.warn)
- Implement finishAssignDestructureExpr for destructuring assignments
- Use parseBlockExpr instead of parseBlock in for/while statement bodies
- Use parseSingleAssignExpr in switch prongs
- Enable x86_64/CodeGen.zig corpus entry
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The @unionInit handler in builtinCallMultiArg was propagating the parent's
result info context (e.g. RI_CTX_RETURN) to the init value expression.
Upstream Zig creates a fresh ResultInfo with .ctx = .none. This caused
call flags mismatch (pop_error_return_trace) in return expressions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
rlBuiltinCall was always returning false (not consuming result location).
The Zig reference marks @frameAddress as consuming the RL (workaround for
llvm/llvm-project#68409), which affects declaration codegen path (pointer
vs value based). Match the upstream behavior.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The AST_NODE_CONTAINER_FIELD case in structDeclInner had an incorrect guard
`if (nd.rhs != 0)` before reading align/value from extra_data. Since rhs is
an extra_data index (not a node), 0 is a valid index. Removing the guard
fixes 3-5 missing instructions in files where the first extra_data entry
happens to be a container_field's align+value.
Also fix clang-format: addBuiltinValue arg wrapping, for-loop semicolons.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Upgrade decimal_float_fits_f64() to use 128-bit integer arithmetic for the
algebraic round-trip test, handling mantissas up to ~38 significant digits.
This fixes float128-vs-float tag mismatches for values that fit in 128-bit
mantissa but overflow 64-bit.
Newly enabled: gpu, memmove, mulf3, udivmodei4, udivmod, scalar, ff,
p256_64, p256_scalar_64, p384_64, p384_scalar_64, secp256k1_64,
secp256k1_scalar_64, sha2, sha3, Decompress, testing, log10, log2, log,
rem_pio2f, rem_pio2_large, rem_pio2.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
decimal_float_fits_f64() incorrectly returned true when a non-zero mantissa
(that had overflowed uint64_t) was converted to 0.0 by strtod. These values
do not fit in f64 and need f128 representation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix strtod underflow/overflow edge cases in decimal_float_fits_f64.
Enables 707 files across lib/std/, lib/compiler_rt/, src/, and more.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>