commit 1ae7c7687f3180b167e4a2f676bddb892a99e28c (tree)
parent 2f6a80043ea1b9cfc2119c5a5e885ab145b218f6
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date: Mon, 23 Feb 2026 20:11:21 +0000
sema_test: zero-copy PrecomputedFunc — point into binary data directly
PrecomputedFunc now stores raw [*]const u8 byte pointers instead of c.Air,
eliminating per-function heap allocations and memcpy in parsePrecomputedAir.
airCompareOne takes two PrecomputedFunc values; C-sema output is wrapped via
precomputedFromCAir.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat:
2 files changed, 138 insertions(+), 164 deletions(-)
diff --git a/stage0/sema_test.zig b/stage0/sema_test.zig
@@ -227,12 +227,20 @@ test "sema: function decl smoke test" {
const air_tag_names = @import("air_tag_names");
/// A parsed function from the pre-computed AIR binary data.
+/// Fields are raw byte pointers into the binary data — no alignment
+/// requirements, no copies. When inst_len == 0 or extra_len == 0 the
+/// corresponding pointer is undefined and must not be dereferenced.
pub const PrecomputedFunc = struct {
name: []const u8,
- air: c.Air,
+ inst_len: u32,
+ tags: [*]const u8,
+ datas: [*]const u8,
+ extra_len: u32,
+ extra: [*]const u8,
};
/// Parse pre-computed AIR from binary data (generated by air_gen).
+/// Zero-copy: pointers point directly into `data`.
/// Binary format:
/// func_count: u32 (little-endian)
/// Per function:
@@ -243,12 +251,12 @@ pub const PrecomputedFunc = struct {
/// inst_datas: [inst_len * 8]u8
/// extra_len: u32
/// extra: [extra_len * 4]u8
-pub fn parsePrecomputedAir(gpa: std.mem.Allocator, data: []const u8) ![]PrecomputedFunc {
+pub fn parsePrecomputedAir(data: []const u8) ![]PrecomputedFunc {
var pos: usize = 0;
const func_count = readU32(data, &pos) orelse return error.InvalidAirData;
- const funcs = try gpa.alloc(PrecomputedFunc, func_count);
- errdefer gpa.free(funcs);
+ const funcs = try std.testing.allocator.alloc(PrecomputedFunc, func_count);
+ errdefer std.testing.allocator.free(funcs);
for (funcs) |*f| {
// name
@@ -257,48 +265,33 @@ pub fn parsePrecomputedAir(gpa: std.mem.Allocator, data: []const u8) ![]Precompu
f.name = data[pos..][0..name_len];
pos += name_len;
- // inst_tags + inst_datas (allocate copies with proper alignment)
+ // inst_tags + inst_datas — point directly into data
const inst_len = readU32(data, &pos) orelse return error.InvalidAirData;
-
- const tags: [*c]u8 = if (inst_len > 0) blk: {
+ f.inst_len = inst_len;
+ if (inst_len > 0) {
if (pos + inst_len > data.len) return error.InvalidAirData;
- const alloc = try gpa.alloc(u8, inst_len);
- @memcpy(alloc, data[pos..][0..inst_len]);
- break :blk alloc.ptr;
- } else null;
- pos += inst_len;
-
- const datas: [*c]c.AirInstData = if (inst_len > 0) blk: {
+ f.tags = data[pos..].ptr;
+ pos += inst_len;
const datas_byte_len = inst_len * 8;
if (pos + datas_byte_len > data.len) return error.InvalidAirData;
- const alloc = try gpa.alloc(c.AirInstData, inst_len);
- const alloc_bytes: [*]u8 = @ptrCast(alloc.ptr);
- @memcpy(alloc_bytes[0..datas_byte_len], data[pos..][0..datas_byte_len]);
- break :blk alloc.ptr;
- } else null;
- pos += inst_len * 8;
-
- // extra (allocate copy with u32 alignment)
+ f.datas = data[pos..].ptr;
+ pos += datas_byte_len;
+ } else {
+ f.tags = undefined;
+ f.datas = undefined;
+ }
+
+ // extra — point directly into data
const extra_len = readU32(data, &pos) orelse return error.InvalidAirData;
- const extra: [*c]u32 = if (extra_len > 0) blk: {
+ f.extra_len = extra_len;
+ if (extra_len > 0) {
const extra_byte_len = extra_len * 4;
if (pos + extra_byte_len > data.len) return error.InvalidAirData;
- const alloc = try gpa.alloc(u32, extra_len);
- const alloc_bytes: [*]u8 = @ptrCast(alloc.ptr);
- @memcpy(alloc_bytes[0..extra_byte_len], data[pos..][0..extra_byte_len]);
- break :blk alloc.ptr;
- } else null;
- pos += extra_len * 4;
-
- f.air = .{
- .inst_len = inst_len,
- .inst_cap = inst_len,
- .inst_tags = tags,
- .inst_datas = datas,
- .extra_len = extra_len,
- .extra_cap = extra_len,
- .extra = extra,
- };
+ f.extra = data[pos..].ptr;
+ pos += extra_byte_len;
+ } else {
+ f.extra = undefined;
+ }
}
return funcs;
@@ -311,13 +304,8 @@ fn readU32(data: []const u8, pos: *usize) ?u32 {
return val;
}
-pub fn freePrecomputedAir(gpa: std.mem.Allocator, funcs: []PrecomputedFunc) void {
- for (funcs) |f| {
- if (f.air.inst_tags) |t| gpa.free(t[0..f.air.inst_len]);
- if (f.air.inst_datas) |d| gpa.free(d[0..f.air.inst_len]);
- if (f.air.extra) |e| gpa.free(e[0..f.air.extra_len]);
- }
- gpa.free(funcs);
+pub fn freePrecomputedAir(funcs: []PrecomputedFunc) void {
+ std.testing.allocator.free(funcs);
}
/// Compare C sema output against pre-computed AIR data.
@@ -331,10 +319,22 @@ pub fn airComparePrecomputed(precomputed: []const PrecomputedFunc, c_func_air_li
std.debug.print("C function '{s}' not found in pre-computed AIR\n", .{c_name});
return error.AirMismatch;
};
- try airCompareOne(c_name, &pf.air, &cf.air);
+ const c_pf = precomputedFromCAir(cf);
+ try airCompareOne(c_name, pf.*, c_pf);
}
}
+fn precomputedFromCAir(cf: *const c.SemaFuncAir) PrecomputedFunc {
+ return .{
+ .name = if (cf.name) |n| std.mem.span(n) else "",
+ .inst_len = cf.air.inst_len,
+ .tags = if (cToOpt(u8, cf.air.inst_tags)) |t| t else undefined,
+ .datas = if (cToOpt(c.AirInstData, cf.air.inst_datas)) |d| @ptrCast(d) else undefined,
+ .extra_len = cf.air.extra_len,
+ .extra = if (cToOpt(u32, cf.air.extra)) |e| @ptrCast(e) else undefined,
+ };
+}
+
fn precomputedFindByName(funcs: []const PrecomputedFunc, name: []const u8) ?*const PrecomputedFunc {
const bare_name = stripModulePrefix(name);
for (funcs) |*f| {
@@ -361,6 +361,10 @@ fn cToOpt(comptime T: type, ptr: [*c]T) ?[*]const T {
return if (ptr == null) null else @ptrCast(ptr);
}
+fn readExtraWord(extra: [*]const u8, index: usize) u32 {
+ return std.mem.readInt(u32, extra[index * 4 ..][0..4], .little);
+}
+
fn airTagNameSlice(tag_val: u8) []const u8 {
return air_tag_names.names[tag_val];
}
@@ -617,45 +621,37 @@ fn normalizeNtsPadding(extra: []u32, nts_index: u32) void {
}
}
-fn airCompareOne(name: []const u8, zig_air: *const c.Air, c_air: *const c.Air) !void {
- if (zig_air.inst_len != c_air.inst_len) {
- std.debug.print("'{s}': inst_len mismatch: zig={d} c={d}\n", .{ name, zig_air.inst_len, c_air.inst_len });
- if (cToOpt(u8, zig_air.inst_tags)) |zt| {
- std.debug.print(" zig tags:", .{});
- for (0..zig_air.inst_len) |j| std.debug.print(" {s}", .{airTagNameSlice(zt[j])});
+fn airCompareOne(name: []const u8, a: PrecomputedFunc, b: PrecomputedFunc) !void {
+ if (a.inst_len != b.inst_len) {
+ std.debug.print("'{s}': inst_len mismatch: a={d} b={d}\n", .{ name, a.inst_len, b.inst_len });
+ if (a.inst_len > 0) {
+ std.debug.print(" a tags:", .{});
+ for (0..a.inst_len) |j| std.debug.print(" {s}", .{airTagNameSlice(a.tags[j])});
std.debug.print("\n", .{});
}
- if (cToOpt(u8, c_air.inst_tags)) |ct| {
- std.debug.print(" c tags:", .{});
- for (0..c_air.inst_len) |j| std.debug.print(" {s}", .{airTagNameSlice(ct[j])});
+ if (b.inst_len > 0) {
+ std.debug.print(" b tags:", .{});
+ for (0..b.inst_len) |j| std.debug.print(" {s}", .{airTagNameSlice(b.tags[j])});
std.debug.print("\n", .{});
}
return error.AirMismatch;
}
- const inst_len = zig_air.inst_len;
+ const inst_len = a.inst_len;
// Canonical ref maps shared between datas and extra comparisons.
- var zig_ref_map = std.AutoHashMap(u32, u32).init(std.testing.allocator);
- defer zig_ref_map.deinit();
- var c_ref_map = std.AutoHashMap(u32, u32).init(std.testing.allocator);
- defer c_ref_map.deinit();
- var next_zig_id: u32 = 0;
- var next_c_id: u32 = 0;
+ var a_ref_map = std.AutoHashMap(u32, u32).init(std.testing.allocator);
+ defer a_ref_map.deinit();
+ var b_ref_map = std.AutoHashMap(u32, u32).init(std.testing.allocator);
+ defer b_ref_map.deinit();
+ var next_a_id: u32 = 0;
+ var next_b_id: u32 = 0;
// Tags
if (inst_len > 0) {
- const zig_tags: [*]const u8 = cToOpt(u8, zig_air.inst_tags) orelse {
- std.debug.print("'{s}': Zig inst_tags is null but inst_len={d}\n", .{ name, inst_len });
- return error.AirMismatch;
- };
- const c_tags: [*]const u8 = cToOpt(u8, c_air.inst_tags) orelse {
- std.debug.print("'{s}': C inst_tags is null but inst_len={d}\n", .{ name, inst_len });
- return error.AirMismatch;
- };
- if (!std.mem.eql(u8, zig_tags[0..inst_len], c_tags[0..inst_len])) {
+ if (!std.mem.eql(u8, a.tags[0..inst_len], b.tags[0..inst_len])) {
std.debug.print("'{s}': tags mismatch (inst_len={d}):", .{ name, inst_len });
for (0..inst_len) |j| {
- std.debug.print(" zig[{d}]={d}({s}) c[{d}]={d}({s})", .{ j, zig_tags[j], airTagNameSlice(zig_tags[j]), j, c_tags[j], airTagNameSlice(c_tags[j]) });
+ std.debug.print(" a[{d}]={d}({s}) b[{d}]={d}({s})", .{ j, a.tags[j], airTagNameSlice(a.tags[j]), j, b.tags[j], airTagNameSlice(b.tags[j]) });
}
std.debug.print("\n", .{});
return error.AirMismatch;
@@ -671,45 +667,35 @@ fn airCompareOne(name: []const u8, zig_air: *const c.Air, c_air: *const c.Air) !
// (un_op, no_op, ty, repeat) leave padding uninitialised — only
// compare the meaningful slots per tag via airInstNumSlots.
if (inst_len > 0) {
- const zig_tags: [*]const u8 = cToOpt(u8, zig_air.inst_tags) orelse unreachable;
- const zig_datas: [*]const u8 = @ptrCast(cToOpt(c.AirInstData, zig_air.inst_datas) orelse {
- std.debug.print("'{s}': Zig inst_datas is null but inst_len={d}\n", .{ name, inst_len });
- return error.AirMismatch;
- });
- const c_datas: [*]const u8 = @ptrCast(cToOpt(c.AirInstData, c_air.inst_datas) orelse {
- std.debug.print("'{s}': C inst_datas is null but inst_len={d}\n", .{ name, inst_len });
- return error.AirMismatch;
- });
-
for (0..inst_len) |j| {
const off = j * 8;
- const tag_val = zig_tags[j];
+ const tag_val = a.tags[j];
const ref_slots = airDataRefSlots(tag_val);
const num_slots = airInstNumSlots(tag_val);
for (0..num_slots) |slot| {
const s = off + slot * 4;
- const zig_word = std.mem.readInt(u32, zig_datas[s..][0..4], .little);
- const c_word = std.mem.readInt(u32, c_datas[s..][0..4], .little);
+ const a_word = std.mem.readInt(u32, a.datas[s..][0..4], .little);
+ const b_word = std.mem.readInt(u32, b.datas[s..][0..4], .little);
// Skip data comparison for dead BLOCKs (tag 51).
// Dead BLOCKs have undefined data in Zig vs zeroed in C.
- // Only check c_word to avoid reading uninitialized Zig data
+ // Only check b_word to avoid reading uninitialized Zig data
// (which triggers valgrind "uninitialised value" errors).
- if (tag_val == 51 and c_word == 0) continue;
+ if (tag_val == 51 and b_word == 0) continue;
if (ref_slots[slot]) {
// This slot is a Ref — canonicalize IP refs.
- const zig_canon = canonicalizeRef(zig_word, &zig_ref_map, &next_zig_id);
- const c_canon = canonicalizeRef(c_word, &c_ref_map, &next_c_id);
- if (zig_canon != c_canon) {
- std.debug.print("'{s}': datas ref mismatch at inst[{d}] slot {d}: zig=0x{x}[{s}] c=0x{x}[{s}] (canon: zig={d} c={d}) (tag={s})\n", .{ name, j, slot, zig_word, refKindStr(zig_word), c_word, refKindStr(c_word), zig_canon, c_canon, airTagNameSlice(tag_val) });
+ const a_canon = canonicalizeRef(a_word, &a_ref_map, &next_a_id);
+ const b_canon = canonicalizeRef(b_word, &b_ref_map, &next_b_id);
+ if (a_canon != b_canon) {
+ std.debug.print("'{s}': datas ref mismatch at inst[{d}] slot {d}: a=0x{x}[{s}] b=0x{x}[{s}] (canon: a={d} b={d}) (tag={s})\n", .{ name, j, slot, a_word, refKindStr(a_word), b_word, refKindStr(b_word), a_canon, b_canon, airTagNameSlice(tag_val) });
return error.AirMismatch;
}
} else {
// Non-ref field — compare directly.
- if (zig_word != c_word) {
- std.debug.print("'{s}': datas mismatch at inst[{d}] slot {d}: zig=0x{x} c=0x{x} (tag={s})\n", .{ name, j, slot, zig_word, c_word, airTagNameSlice(tag_val) });
+ if (a_word != b_word) {
+ std.debug.print("'{s}': datas mismatch at inst[{d}] slot {d}: a=0x{x} b=0x{x} (tag={s})\n", .{ name, j, slot, a_word, b_word, airTagNameSlice(tag_val) });
return error.AirMismatch;
}
}
@@ -718,24 +704,24 @@ fn airCompareOne(name: []const u8, zig_air: *const c.Air, c_air: *const c.Air) !
}
// Extra
- if (zig_air.extra_len != c_air.extra_len) {
- std.debug.print("'{s}': extra_len mismatch: zig={d} c={d}\n", .{ name, zig_air.extra_len, c_air.extra_len });
+ if (a.extra_len != b.extra_len) {
+ std.debug.print("'{s}': extra_len mismatch: a={d} b={d}\n", .{ name, a.extra_len, b.extra_len });
// Print first divergence point
- const min_len = @min(zig_air.extra_len, c_air.extra_len);
+ const min_len = @min(a.extra_len, b.extra_len);
if (min_len > 0) {
- const zig_e: [*]const u32 = cToOpt(u32, zig_air.extra).?;
- const c_e: [*]const u32 = cToOpt(u32, c_air.extra).?;
var printed: u32 = 0;
for (0..min_len) |ei| {
- if (zig_e[ei] != c_e[ei] and printed < 40) {
- std.debug.print(" extra[{d}]: zig={d} c={d}\n", .{ ei, zig_e[ei], c_e[ei] });
+ const a_val = readExtraWord(a.extra, ei);
+ const b_val = readExtraWord(b.extra, ei);
+ if (a_val != b_val and printed < 40) {
+ std.debug.print(" extra[{d}]: a={d} b={d}\n", .{ ei, a_val, b_val });
printed += 1;
}
}
// Also dump the raw extra arrays around the first divergence
var first_diff: usize = min_len;
for (0..min_len) |ei| {
- if (zig_e[ei] != c_e[ei]) {
+ if (readExtraWord(a.extra, ei) != readExtraWord(b.extra, ei)) {
first_diff = ei;
break;
}
@@ -743,96 +729,85 @@ fn airCompareOne(name: []const u8, zig_air: *const c.Air, c_air: *const c.Air) !
if (first_diff < min_len) {
const start = if (first_diff > 5) first_diff - 5 else 0;
const end = @min(first_diff + 20, min_len);
- std.debug.print(" zig extra[{d}..{d}]:", .{ start, end });
- for (start..end) |ei| std.debug.print(" {d}", .{zig_e[ei]});
- std.debug.print("\n c extra[{d}..{d}]:", .{ start, end });
- for (start..end) |ei| std.debug.print(" {d}", .{c_e[ei]});
+ std.debug.print(" a extra[{d}..{d}]:", .{ start, end });
+ for (start..end) |ei| std.debug.print(" {d}", .{readExtraWord(a.extra, ei)});
+ std.debug.print("\n b extra[{d}..{d}]:", .{ start, end });
+ for (start..end) |ei| std.debug.print(" {d}", .{readExtraWord(b.extra, ei)});
std.debug.print("\n", .{});
}
}
return error.AirMismatch;
}
- const extra_len = zig_air.extra_len;
+ const extra_len = a.extra_len;
if (extra_len > 0) {
- const zig_extra: [*]const u32 = cToOpt(u32, zig_air.extra) orelse {
- std.debug.print("'{s}': Zig extra is null but extra_len={d}\n", .{ name, extra_len });
- return error.AirMismatch;
- };
- const c_extra: [*]const u32 = cToOpt(u32, c_air.extra) orelse {
- std.debug.print("'{s}': C extra is null but extra_len={d}\n", .{ name, extra_len });
- return error.AirMismatch;
- };
// Make mutable copies and normalize NullTerminatedString padding.
// Zig's appendAirString leaves trailing bytes uninitialised (0xaa
// in debug); the C side zeroes them. Normalise both to zero.
- const zig_extra_copy = try std.testing.allocator.alloc(u32, extra_len);
- defer std.testing.allocator.free(zig_extra_copy);
- @memcpy(zig_extra_copy, zig_extra[0..extra_len]);
- const c_extra_copy = try std.testing.allocator.alloc(u32, extra_len);
- defer std.testing.allocator.free(c_extra_copy);
- @memcpy(c_extra_copy, c_extra[0..extra_len]);
+ const a_extra_copy = try std.testing.allocator.alloc(u32, extra_len);
+ defer std.testing.allocator.free(a_extra_copy);
+ @memcpy(std.mem.sliceAsBytes(a_extra_copy), a.extra[0 .. extra_len * 4]);
+ const b_extra_copy = try std.testing.allocator.alloc(u32, extra_len);
+ defer std.testing.allocator.free(b_extra_copy);
+ @memcpy(std.mem.sliceAsBytes(b_extra_copy), b.extra[0 .. extra_len * 4]);
if (inst_len > 0) {
- const tags: [*]const u8 = cToOpt(u8, zig_air.inst_tags).?;
- const zig_datas_raw: [*]const u8 = @ptrCast(cToOpt(c.AirInstData, zig_air.inst_datas).?);
- const c_datas_raw: [*]const u8 = @ptrCast(cToOpt(c.AirInstData, c_air.inst_datas).?);
for (0..inst_len) |j| {
- if (tags[j] == c.AIR_INST_DBG_VAR_VAL or
- tags[j] == c.AIR_INST_DBG_VAR_PTR or
- tags[j] == c.AIR_INST_DBG_ARG_INLINE)
+ if (a.tags[j] == c.AIR_INST_DBG_VAR_VAL or
+ a.tags[j] == c.AIR_INST_DBG_VAR_PTR or
+ a.tags[j] == c.AIR_INST_DBG_ARG_INLINE)
{
// pl_op: slot 0 = operand, slot 1 = payload (NullTerminatedString)
- const zig_nts = std.mem.readInt(u32, zig_datas_raw[j * 8 + 4 ..][0..4], .little);
- const c_nts = std.mem.readInt(u32, c_datas_raw[j * 8 + 4 ..][0..4], .little);
- normalizeNtsPadding(zig_extra_copy, zig_nts);
- normalizeNtsPadding(c_extra_copy, c_nts);
+ const a_nts = std.mem.readInt(u32, a.datas[j * 8 + 4 ..][0..4], .little);
+ const b_nts = std.mem.readInt(u32, b.datas[j * 8 + 4 ..][0..4], .little);
+ normalizeNtsPadding(a_extra_copy, a_nts);
+ normalizeNtsPadding(b_extra_copy, b_nts);
}
- if (tags[j] == c.AIR_INST_DBG_INLINE_BLOCK) {
+ if (a.tags[j] == c.AIR_INST_DBG_INLINE_BLOCK) {
// ty_pl: slot 1 = payload (extra index).
// Extra layout: {func(IP ref), body_len, body...}
// Canonicalize the func IP ref.
- const zig_payload = std.mem.readInt(u32, zig_datas_raw[j * 8 + 4 ..][0..4], .little);
- const c_payload = std.mem.readInt(u32, c_datas_raw[j * 8 + 4 ..][0..4], .little);
- if (zig_payload < extra_len and c_payload < extra_len) {
- zig_extra_copy[zig_payload] = canonicalizeRef(zig_extra_copy[zig_payload], &zig_ref_map, &next_zig_id);
- c_extra_copy[c_payload] = canonicalizeRef(c_extra_copy[c_payload], &c_ref_map, &next_c_id);
+ const a_payload = std.mem.readInt(u32, a.datas[j * 8 + 4 ..][0..4], .little);
+ const b_payload = std.mem.readInt(u32, b.datas[j * 8 + 4 ..][0..4], .little);
+ if (a_payload < extra_len and b_payload < extra_len) {
+ a_extra_copy[a_payload] = canonicalizeRef(a_extra_copy[a_payload], &a_ref_map, &next_a_id);
+ b_extra_copy[b_payload] = canonicalizeRef(b_extra_copy[b_payload], &b_ref_map, &next_b_id);
}
}
- if (tags[j] == c.AIR_INST_CALL or
- tags[j] == c.AIR_INST_CALL_ALWAYS_TAIL or
- tags[j] == c.AIR_INST_CALL_NEVER_TAIL or
- tags[j] == c.AIR_INST_CALL_NEVER_INLINE)
+ if (a.tags[j] == c.AIR_INST_CALL or
+ a.tags[j] == c.AIR_INST_CALL_ALWAYS_TAIL or
+ a.tags[j] == c.AIR_INST_CALL_NEVER_TAIL or
+ a.tags[j] == c.AIR_INST_CALL_NEVER_INLINE)
{
// pl_op: slot 1 = payload (extra index).
// Extra layout: {args_len, arg_refs[0..args_len]}
// Canonicalize arg refs (they may be IP refs).
- const zig_payload = std.mem.readInt(u32, zig_datas_raw[j * 8 + 4 ..][0..4], .little);
- const c_payload = std.mem.readInt(u32, c_datas_raw[j * 8 + 4 ..][0..4], .little);
- if (zig_payload < extra_len and c_payload < extra_len) {
- const zig_args_len = zig_extra_copy[zig_payload];
- const c_args_len = c_extra_copy[c_payload];
+ const a_payload = std.mem.readInt(u32, a.datas[j * 8 + 4 ..][0..4], .little);
+ const b_payload = std.mem.readInt(u32, b.datas[j * 8 + 4 ..][0..4], .little);
+ if (a_payload < extra_len and b_payload < extra_len) {
+ const a_args_len = a_extra_copy[a_payload];
+ const b_args_len = b_extra_copy[b_payload];
var ai: u32 = 0;
- while (ai < zig_args_len and ai < c_args_len) : (ai += 1) {
- const zi = zig_payload + 1 + ai;
- const ci = c_payload + 1 + ai;
- if (zi < extra_len and ci < extra_len) {
- zig_extra_copy[zi] = canonicalizeRef(zig_extra_copy[zi], &zig_ref_map, &next_zig_id);
- c_extra_copy[ci] = canonicalizeRef(c_extra_copy[ci], &c_ref_map, &next_c_id);
+ while (ai < a_args_len and ai < b_args_len) : (ai += 1) {
+ const a_idx = a_payload + 1 + ai;
+ const b_idx = b_payload + 1 + ai;
+ if (a_idx < extra_len and b_idx < extra_len) {
+ a_extra_copy[a_idx] = canonicalizeRef(a_extra_copy[a_idx], &a_ref_map, &next_a_id);
+ b_extra_copy[b_idx] = canonicalizeRef(b_extra_copy[b_idx], &b_ref_map, &next_b_id);
}
}
}
}
}
}
- if (!std.mem.eql(u32, zig_extra_copy, c_extra_copy)) {
+ if (!std.mem.eql(u32, a_extra_copy, b_extra_copy)) {
std.debug.print("'{s}': extra mismatch (extra_len={d})\n", .{ name, extra_len });
- std.debug.print(" zig extra:", .{});
- for (0..extra_len) |ei| std.debug.print(" {d}", .{zig_extra_copy[ei]});
- std.debug.print("\n c extra:", .{});
- for (0..extra_len) |ei| std.debug.print(" {d}", .{c_extra_copy[ei]});
+ std.debug.print(" a extra:", .{});
+ for (0..extra_len) |ei| std.debug.print(" {d}", .{a_extra_copy[ei]});
+ std.debug.print("\n b extra:", .{});
+ for (0..extra_len) |ei| std.debug.print(" {d}", .{b_extra_copy[ei]});
std.debug.print("\n", .{});
for (0..extra_len) |ei| {
- if (zig_extra_copy[ei] != c_extra_copy[ei]) {
- std.debug.print(" extra[{d}]: zig=0x{x} c=0x{x}\n", .{ ei, zig_extra_copy[ei], c_extra_copy[ei] });
+ if (a_extra_copy[ei] != b_extra_copy[ei]) {
+ std.debug.print(" extra[{d}]: a=0x{x} b=0x{x}\n", .{ ei, a_extra_copy[ei], b_extra_copy[ei] });
}
}
return error.AirMismatch;
@@ -843,7 +818,6 @@ fn airCompareOne(name: []const u8, zig_air: *const c.Air, c_air: *const c.Air) !
const corpus = @import("corpus.zig");
test "sema air: unit tests" {
- const gpa = std.testing.allocator;
@setEvalBranchQuota(corpus.sema_unit_tests.len * 2);
inline for (corpus.sema_unit_tests) |path| {
const source: [:0]const u8 = @embedFile("../" ++ path);
@@ -851,8 +825,8 @@ test "sema air: unit tests" {
defer result.deinit();
const air_data = @import("air_data").getData(path);
- const precomputed = try parsePrecomputedAir(gpa, air_data);
- defer freePrecomputedAir(gpa, precomputed);
+ const precomputed = try parsePrecomputedAir(air_data);
+ defer freePrecomputedAir(precomputed);
airComparePrecomputed(precomputed, result.c_func_air_list) catch {
std.debug.print("FAIL: {s}\n", .{path});
return error.TestFailed;
diff --git a/stage0/stages_test.zig b/stage0/stages_test.zig
@@ -91,8 +91,8 @@ fn stagesCheck(gpa: Allocator, comptime path: []const u8, source: [:0]const u8)
defer sc.semaFuncAirListDeinit(&c_func_air_list);
const air_data = @import("air_data").getData(path);
- const precomputed = try sema_test.parsePrecomputedAir(gpa, air_data);
- defer sema_test.freePrecomputedAir(gpa, precomputed);
+ const precomputed = try sema_test.parsePrecomputedAir(air_data);
+ defer sema_test.freePrecomputedAir(precomputed);
try sema_test.airComparePrecomputed(precomputed, c_func_air_list);
}
}