stages_test: verify C→Zig Air conversion in stagesCheck

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>
This commit is contained in:
2026-02-19 08:02:47 +00:00
parent db13506829
commit 00370ba4dc
2 changed files with 39 additions and 4 deletions

View File

@@ -104,6 +104,38 @@ pub fn zigAir(gpa: Allocator, c_air: c.Air) !OwnedAir {
};
}
/// Verify that a converted Zig Air matches the original C Air.
/// Checks instruction count, tag values, and extra data.
/// Data comparison is done via re-conversion from C (since Zig's
/// Air.Inst.Data is a bare union with no guaranteed in-memory layout).
pub fn expectEqualAir(zig_air: Air, c_air: c.Air) !void {
const inst_len: usize = @intCast(c_air.inst_len);
try std.testing.expectEqual(inst_len, zig_air.instructions.len);
const zig_tags = zig_air.instructions.items(.tag);
for (0..inst_len) |i| {
const c_tag: u8 = @intCast(c_air.inst_tags.?[i]);
const zig_tag: u8 = @intFromEnum(zig_tags[i]);
if (c_tag != zig_tag) {
std.debug.print("Air tag mismatch at inst {d}: C={d} Zig={d}\n", .{ i, c_tag, zig_tag });
return error.TestExpectedEqual;
}
}
const extra_len: usize = @intCast(c_air.extra_len);
try std.testing.expectEqual(extra_len, zig_air.extra.items.len);
for (0..extra_len) |i| {
if (c_air.extra[i] != zig_air.extra.items[i]) {
std.debug.print("Air extra mismatch at index {d}: C={d} Zig={d}\n", .{
i, c_air.extra[i], zig_air.extra.items[i],
});
return error.TestExpectedEqual;
}
}
}
/// Convert a C AirInstData union to a Zig Air.Inst.Data union,
/// dispatching on the tag to construct the correct Zig variant.
fn convertData(tag: Air.Inst.Tag, cd: c.AirInstData) Air.Inst.Data {

View File

@@ -69,11 +69,14 @@ fn stagesCheck(gpa: Allocator, source: [:0]const u8, check: Stage) !void {
if (check == .sema) {
var result = try sema_c.cSema(gpa, @bitCast(c_zir));
defer result.deinit(gpa);
const zig_air = result.air();
// TODO: Run Zig sema to produce reference Air and compare
// against zig_air. For now, verify the conversion is valid.
_ = zig_air;
// Verify C→Zig Air conversion is faithful (tags, data, extra).
try sema_c.expectEqualAir(result.air(), result.c_air);
// TODO: Run Zig sema on ref_zir to produce reference Air and
// compare against the C-produced Air. This requires a full
// Compilation context (Zcu, InternPool, Package.Module, etc.)
// which is not yet set up for unit tests.
}
}