From f7f3d24984deb81deb9bcfe99b4eb37e8d7215bf Mon Sep 17 00:00:00 2001 From: Pavel Verigo Date: Wed, 30 Sep 2026 05:18:52 +0200 Subject: [PATCH 1/6] wasm: undefined allowed limit only to == .strong --- src/link/Wasm.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 313d5dcd8cf9ba85242a89de43ba50c93ae8dddc..6e77b0f1f8a251c11b1027ce442ed15971711613 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -2721,13 +2721,13 @@ pub const FunctionImportId = enum(u32) { return switch (unpack(id, wasm)) { .object_function_import => |i| { const import = i.value(wasm); - return import.flags.binding == .strong and import.module_name != .none; + return import.flags.binding == .strong; }, .zcu_import => |i| { const zcu = wasm.base.comp.zcu.?; const ip = &zcu.intern_pool; const ext = ip.indexToKey(ip.getNav(i.ptr(wasm).*).resolved.?.value).@"extern"; - return ext.linkage != .weak and ext.lib_name != .none; + return ext.linkage == .strong; }, }; } -- 2.54.0 From 2d361f612b426fa44861caa2ff54c716a4dd5c89 Mon Sep 17 00:00:00 2001 From: Pavel Verigo Date: Wed, 30 Sep 2026 20:57:45 +0300 Subject: [PATCH 2/6] wasm: test and fix compilation of mvp/lime1/wasm_v3_0 mcpu --- lib/std/Build/Configuration.zig | 2 +- lib/std/atomic.zig | 2 + lib/std/wasm.zig | 6 +- src/codegen/wasm/CodeGen.zig | 104 ++++++++++++++++++++++++-------- test/behavior/atomics.zig | 1 + test/tests.zig | 21 +++++++ 6 files changed, 108 insertions(+), 28 deletions(-) diff --git a/lib/std/Build/Configuration.zig b/lib/std/Build/Configuration.zig index e85e19cd1e7d7ba37128ab208de61e4e39690a3e..5e5cd36e22ff0b4234f29414a95c874be5a42d87 100644 --- a/lib/std/Build/Configuration.zig +++ b/lib/std/Build/Configuration.zig @@ -2563,7 +2563,7 @@ pub const TargetQuery = struct { .cpu = .{ .arch = cpu_arch, .model = cpu_arch.parseCpuModel(tq.cpu_name.value.?.slice(c)).?, - .features = tq.cpu_features_add.value.?, + .features = tq.cpu_features_add.value orelse .empty, }, .os = .{ .tag = os_tag, diff --git a/lib/std/atomic.zig b/lib/std/atomic.zig index abc7b06f0adbfb51e58d33492282780564c06e3a..f3f39b90a96352b943bfda1a091db404ad64d174 100644 --- a/lib/std/atomic.zig +++ b/lib/std/atomic.zig @@ -160,6 +160,8 @@ test Value { } test "Value.swap" { + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + var x = Value(usize).init(5); try testing.expectEqual(@as(usize, 5), x.swap(10, .seq_cst)); try testing.expectEqual(@as(usize, 10), x.load(.seq_cst)); diff --git a/lib/std/wasm.zig b/lib/std/wasm.zig index e8cd89952e2816633ef494e48ed054f7e0ff48c0..e6dfa535b39e6073bc5114568b626d9db8f9719b 100644 --- a/lib/std/wasm.zig +++ b/lib/std/wasm.zig @@ -514,9 +514,9 @@ pub const AtomicsOpcode = enum(u32) { i64_atomic_rmw32_add_u = 0x24, i32_atomic_rmw_sub = 0x25, i64_atomic_rmw_sub = 0x26, - i32_atomic_rmw8_sub_u = 0x27A, - i32_atomic_rmw16_sub_u = 0x28A, - i64_atomic_rmw8_sub_u = 0x29A, + i32_atomic_rmw8_sub_u = 0x27, + i32_atomic_rmw16_sub_u = 0x28, + i64_atomic_rmw8_sub_u = 0x29, i64_atomic_rmw16_sub_u = 0x2A, i64_atomic_rmw32_sub_u = 0x2B, i32_atomic_rmw_and = 0x2C, diff --git a/src/codegen/wasm/CodeGen.zig b/src/codegen/wasm/CodeGen.zig index 2e894ef2c87755c64808405863584b2c38ca7eda..c464928168910f7509ebd9bbc3da1544dcb52834 100644 --- a/src/codegen/wasm/CodeGen.zig +++ b/src/codegen/wasm/CodeGen.zig @@ -1338,11 +1338,21 @@ const SimdStoreStrategy = enum { /// it using a instruction, rather than an unrolled version. pub fn determineSimdStoreStrategy(ty: Type, zcu: *const Zcu, target: *const std.Target) SimdStoreStrategy { assert(ty.zigTypeTag(zcu) == .vector); - if (ty.bitSize(zcu) != 128) return .unrolled; - if (target.cpu.has(.wasm, .relaxed_simd) or target.cpu.has(.wasm, .simd128)) { - return .direct; - } - return .unrolled; + if (!target.cpu.has(.wasm, .simd128)) return .unrolled; + return switch (ty.toIntern()) { + .vector_16_i8_type, + .vector_16_u8_type, + .vector_8_i16_type, + .vector_8_u16_type, + .vector_4_i32_type, + .vector_4_u32_type, + .vector_2_i64_type, + .vector_2_u64_type, + .vector_4_f32_type, + .vector_2_f64_type, + => .direct, + else => .unrolled, + }; } fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { @@ -5188,12 +5198,27 @@ fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue { } else { return .{ .imm32 = @intFromBool(!val.isNull(zcu)) }; }, - .aggregate => switch (ip.indexToKey(ty.ip_index)) { - .array_type => return cg.fail("Wasm TODO: LowerConstant for {f}", .{ty.fmt(zcu)}), - .vector_type => { + .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) { + .array_type => unreachable, + .vector_type => |vector_type| { assert(determineSimdStoreStrategy(ty, zcu, cg.target) == .direct); var buf: [16]u8 = undefined; - val.writeToMemory(zcu, &buf) catch unreachable; + const elem_size: usize = @intCast(Type.fromInterned(vector_type.child).abiSize(zcu)); + for (0..vector_type.len) |i| { + const dest = buf[i * elem_size ..][0..elem_size]; + const elem: Value = switch (aggregate.storage) { + .bytes => |bytes| { + dest[0] = bytes.at(i, ip); + continue; + }, + .elems => |elems| .fromInterned(elems[i]), + .repeated_elem => |elem| .fromInterned(elem), + }; + elem.writeToMemory(zcu, dest) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.ReinterpretDeclRef, error.IllDefinedMemoryLayout => unreachable, + }; + } return cg.storeSimdImmd(buf); }, .struct_type => unreachable, // packed structs use `bitpack` @@ -5216,6 +5241,7 @@ fn storeSimdImmd(cg: *CodeGen, value: [16]u8) !WValue { fn emitUndefined(cg: *CodeGen, ty: Type) InnerError!WValue { const zcu = cg.pt.zcu; switch (ty.zigTypeTag(zcu)) { + .vector => return cg.storeSimdImmd(@splat(0xaa)), .bool, .error_set => return .{ .imm32 = 0xaaaaaaaa }, .int, .@"enum" => switch (ty.intInfo(zcu).bits) { 0...32 => return .{ .imm32 = 0xaaaaaaaa }, @@ -5785,7 +5811,7 @@ fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerErro .f80, .f128 => unreachable, }, .int => {}, - .aggregate => unreachable, + .aggregate => return operand, // both v128 } switch (dest_class) { @@ -6991,22 +7017,49 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const result: WValue = result_value: { switch (result_ty.zigTypeTag(zcu)) { .array, .vector => { - const result = try cg.allocStack(result_ty); const elem_ty = result_ty.childType(zcu); - const elem_size = elem_ty.abiSize(zcu); - const sentinel = result_ty.sentinel(zcu); + if (isByRef(result_ty, zcu, cg.target)) { + const result = try cg.allocStack(result_ty); + const elem_size = elem_ty.abiSize(zcu); + const sentinel = result_ty.sentinel(zcu); - var offset: u64 = 0; - for (elements) |elem| { - const elem_val = try cg.resolveInst(elem); - try cg.store(result, elem_val, elem_ty, .{ .offset = offset }); - offset += elem_size; - } - if (sentinel) |s| { - const val = try cg.resolveValue(s); - try cg.store(result, val, elem_ty, .{ .offset = offset }); + var offset: u64 = 0; + for (elements) |elem| { + const elem_val = try cg.resolveInst(elem); + try cg.store(result, elem_val, elem_ty, .{ .offset = offset }); + offset += elem_size; + } + if (sentinel) |s| { + const val = try cg.resolveValue(s); + try cg.store(result, val, elem_ty, .{ .offset = offset }); + } + break :result_value result; + } else { + assert(result_ty.zigTypeTag(zcu) == .vector); + const splat: std.wasm.SimdOpcode, const replace_lane: std.wasm.SimdOpcode = switch (elem_ty.toIntern()) { + .u8_type, .i8_type => .{ .i8x16_splat, .i8x16_replace_lane }, + .u16_type, .i16_type => .{ .i16x8_splat, .i16x8_replace_lane }, + .u32_type, .i32_type => .{ .i32x4_splat, .i32x4_replace_lane }, + .u64_type, .i64_type => .{ .i64x2_splat, .i64x2_replace_lane }, + .f32_type => .{ .f32x4_splat, .f32x4_replace_lane }, + .f64_type => .{ .f64x2_splat, .f64x2_replace_lane }, + else => unreachable, + }; + + // TODO: find best element to splat, if it is constant dont use splat at all + try cg.emitWValue(try cg.resolveInst(elements[0])); + const splat_extra: u32 = @intCast(cg.mir_extra.items.len); + try cg.mir_extra.append(cg.gpa, @backingInt(splat)); + try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = splat_extra } }); + for (elements[1..], 1..) |elem, lane| { + if (elem == elements[0]) continue; + try cg.emitWValue(try cg.resolveInst(elem)); + const extra_index: u32 = @intCast(cg.mir_extra.items.len); + try cg.mir_extra.appendSlice(cg.gpa, &.{ @backingInt(replace_lane), @intCast(lane) }); + try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); + } + break :result_value .stack; } - break :result_value result; }, .@"struct" => switch (result_ty.containerLayout(zcu)) { .@"packed" => unreachable, // legalize .expand_packed_aggregate_init @@ -7633,7 +7686,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { 1 => .i32_atomic_rmw8_cmpxchg_u, 2 => .i32_atomic_rmw16_cmpxchg_u, 4 => .i32_atomic_rmw_cmpxchg, - 8 => .i32_atomic_rmw_cmpxchg, + 8 => .i64_atomic_rmw_cmpxchg, else => |size| return cg.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}), }, .{ .offset = ptr_operand.memOffset(), @@ -7721,6 +7774,9 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const op: std.lang.AtomicRmwOp = extra.op(); if (cg.useAtomicFeature()) { + if (ty.isAnyFloat()) { + return cg.fail("TODO: atomic rmw on floats", .{}); + } const int_ty: IntType = .fromType(cg, ty); switch (op) { .Max, diff --git a/test/behavior/atomics.zig b/test/behavior/atomics.zig index e53a4c818fb7e1a911a6ecee4e171ba67b37cfe2..baae51590e637e312967b6e6bed00a61fcdb2f15 100644 --- a/test/behavior/atomics.zig +++ b/test/behavior/atomics.zig @@ -184,6 +184,7 @@ fn testAtomicStore() !void { } test "atomicrmw with floats" { + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO diff --git a/test/tests.zig b/test/tests.zig index ba0079b752ffb808a2cebe89fb5776e1663aa34f..24f71fa01adb71646c49bd4db5b6a0bd57bea8b2 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -1612,6 +1612,27 @@ const module_test_targets = blk: { .{ .target = .{ .cpu_arch = .wasm32, + .cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp }, + .os_tag = .wasi, + .abi = .none, + }, + .use_llvm = false, + .use_lld = false, + }, + .{ + .target = .{ + .cpu_arch = .wasm32, + .cpu_model = .{ .explicit = &std.Target.wasm.cpu.lime1 }, + .os_tag = .wasi, + .abi = .none, + }, + .use_llvm = false, + .use_lld = false, + }, + .{ + .target = .{ + .cpu_arch = .wasm32, + .cpu_model = .{ .explicit = &std.Target.wasm.cpu.wasm_v3_0 }, .os_tag = .wasi, .abi = .none, }, -- 2.54.0 From 56fad80e8ce14a23f6642e73f545ed6c8b394929 Mon Sep 17 00:00:00 2001 From: Pavel Verigo Date: Sat, 17 Oct 2026 01:21:20 +0200 Subject: [PATCH 3/6] wasm: fix switch on wide integers and ?error repr --- src/codegen/wasm/CodeGen.zig | 23 +++--- test/behavior/optional.zig | 33 ++++++++ test/behavior/switch.zig | 146 +++++++++++++++++++++++++++++------ 3 files changed, 169 insertions(+), 33 deletions(-) diff --git a/src/codegen/wasm/CodeGen.zig b/src/codegen/wasm/CodeGen.zig index c464928168910f7509ebd9bbc3da1544dcb52834..90da3698142b255453c955a95b1b2af91ca39a79 100644 --- a/src/codegen/wasm/CodeGen.zig +++ b/src/codegen/wasm/CodeGen.zig @@ -2599,17 +2599,11 @@ const IntType = struct { .one, .many, .c => .{ .is_signed = false, .bits = cg.target.ptrBitWidth() }, .slice => unreachable, }, - .opt_type => |opt_child| return if (!Type.fromInterned(opt_child).hasRuntimeBits(zcu)) - .{ .is_signed = false, .bits = 1 } - else switch (ip.indexToKey(opt_child)) { - .ptr_type => |ptr_type| switch (ptr_type.flags.size) { - .one, .many => switch (ptr_type.flags.is_allowzero) { - false => .{ .is_signed = false, .bits = cg.target.ptrBitWidth() }, - true => unreachable, - }, - .slice, .c => unreachable, - }, - else => unreachable, + .opt_type => |opt_child| { + if (!Type.fromInterned(opt_child).hasRuntimeBits(zcu)) + return .{ .is_signed = false, .bits = 1 }; + assert(Type.fromInterned(ty_index).optionalReprIsPayload(zcu)); + ty_index = opt_child; }, .error_union_type => |error_union_type| return if (!Type.fromInterned(error_union_type.payload_type) .hasRuntimeBits(zcu)) .{ .is_signed = false, .bits = zcu.errorSetBits() } else unreachable, @@ -6039,6 +6033,13 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner if (use_br_table) { const width = width_maybe.?; + if (int_ty.bits > 32) { + _ = try cg.intCmp(int_ty, .lt, target, try cg.resolveValue(min.?)); + try cg.addLabel(.br_if, branch_count - 1); + _ = try cg.intCmp(int_ty, .gt, target, try cg.resolveValue(max.?)); + try cg.addLabel(.br_if, branch_count - 1); + } + const br_value_original = try cg.intSub(int_ty, target, try cg.resolveValue(min.?)); _ = try cg.intCast(.u32, int_ty, br_value_original); diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig index 4a6695fd5ec46df9bb5abb5b86de558a4a136ab6..f8e36204603a2eb991c13eaa4fd3e4c8e0406018 100644 --- a/test/behavior/optional.zig +++ b/test/behavior/optional.zig @@ -58,6 +58,39 @@ fn testNullPtrsEql() !void { try expect(&number == x); } +test "optional error equality" { + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + + const S = struct { + fn testEql(comptime T: type, a: ?T, b: ?T, equal: bool) !void { + try expect((a == b) == equal); + try expect((a != b) == !equal); + } + + fn doTheTest() !void { + try testEql(error{}, null, null, true); + + try testEql(error{ A, B }, null, null, true); + try testEql(error{ A, B }, error.A, error.A, true); + try testEql(error{ A, B }, error.A, error.B, false); + try testEql(error{ A, B }, null, error.A, false); + try testEql(error{ A, B }, error.A, null, false); + + try testEql(anyerror, null, null, true); + try testEql(anyerror, error.A, error.A, true); + try testEql(anyerror, error.A, error.B, false); + try testEql(anyerror, null, error.A, false); + try testEql(anyerror, error.A, null, false); + } + }; + + try S.doTheTest(); + try comptime S.doTheTest(); +} + test "optional with zero-bit type" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig index 1533d6d5693c7b6e283eab6653d8e018ea0c2d33..151d08c116cc7e4b2f3c120a43f0de93bc357ae2 100644 --- a/test/behavior/switch.zig +++ b/test/behavior/switch.zig @@ -47,34 +47,136 @@ test "switch arbitrary int size" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO - try expect(testSwitchArbInt(u64, 0) == 0); - try expect(testSwitchArbInt(u64, 12) == 1); - try expect(testSwitchArbInt(u64, maxInt(u64)) == 2); - try expect(testSwitchArbInt(u64, 5555) == 3); + const S = struct { + fn testSwitchArbInt(comptime T: type, x: T) u32 { + return switch (x) { + minInt(T) => 0, + 10...15 => 1, + maxInt(T) => 2, + else => 3, + }; + } - try expect(testSwitchArbInt(i64, minInt(i64)) == 0); - try expect(testSwitchArbInt(i64, 12) == 1); - try expect(testSwitchArbInt(i64, maxInt(i64)) == 2); - try expect(testSwitchArbInt(i64, -1000) == 3); + fn doTheTest() !void { + try expect(testSwitchArbInt(u64, 0) == 0); + try expect(testSwitchArbInt(u64, 12) == 1); + try expect(testSwitchArbInt(u64, maxInt(u64)) == 2); + try expect(testSwitchArbInt(u64, 5555) == 3); - try expect(testSwitchArbInt(u128, 0) == 0); - try expect(testSwitchArbInt(u128, 12) == 1); - try expect(testSwitchArbInt(u128, maxInt(u128)) == 2); - try expect(testSwitchArbInt(u128, 5555) == 3); + try expect(testSwitchArbInt(i64, minInt(i64)) == 0); + try expect(testSwitchArbInt(i64, 12) == 1); + try expect(testSwitchArbInt(i64, maxInt(i64)) == 2); + try expect(testSwitchArbInt(i64, -1000) == 3); - try expect(testSwitchArbInt(i128, minInt(i128)) == 0); - try expect(testSwitchArbInt(i128, 12) == 1); - try expect(testSwitchArbInt(i128, maxInt(i128)) == 2); - try expect(testSwitchArbInt(i128, -1000) == 3); + try expect(testSwitchArbInt(u128, 0) == 0); + try expect(testSwitchArbInt(u128, 12) == 1); + try expect(testSwitchArbInt(u128, maxInt(u128)) == 2); + try expect(testSwitchArbInt(u128, 5555) == 3); + + try expect(testSwitchArbInt(i128, minInt(i128)) == 0); + try expect(testSwitchArbInt(i128, 12) == 1); + try expect(testSwitchArbInt(i128, maxInt(i128)) == 2); + try expect(testSwitchArbInt(i128, -1000) == 3); + } + }; + + try S.doTheTest(); + try comptime S.doTheTest(); } -fn testSwitchArbInt(comptime T: type, x: T) u32 { - return switch (x) { - minInt(T) => 0, - 10...15 => 1, - maxInt(T) => 2, - else => 3, +test "dense switch" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; + + const S = struct { + fn unsigned(comptime T: type, x: T) u8 { + return switch (x) { + 0 => 0, + 1 => 1, + 2 => 2, + 3 => 3, + else => 4, + }; + } + + fn signed(comptime T: type, x: T) u8 { + return switch (x) { + -2 => 0, + -1 => 1, + 0 => 2, + 1 => 3, + else => 4, + }; + } + + fn doTheTest() !void { + try expect(unsigned(u32, 0) == 0); + try expect(unsigned(u32, 1) == 1); + try expect(unsigned(u32, 2) == 2); + try expect(unsigned(u32, 3) == 3); + try expect(unsigned(u32, maxInt(u32)) == 4); + try expect(unsigned(u32, (1 << 16) + 1) == 4); + + try expect(signed(i32, -2) == 0); + try expect(signed(i32, -1) == 1); + try expect(signed(i32, 0) == 2); + try expect(signed(i32, 1) == 3); + try expect(signed(i32, minInt(i32)) == 4); + try expect(signed(i32, -(1 << 16) - 2) == 4); + try expect(signed(i32, (1 << 16) + 1) == 4); + + try expect(unsigned(u64, 0) == 0); + try expect(unsigned(u64, 1) == 1); + try expect(unsigned(u64, 2) == 2); + try expect(unsigned(u64, 3) == 3); + try expect(unsigned(u64, maxInt(u64)) == 4); + try expect(unsigned(u64, (1 << 32) + 1) == 4); + + try expect(signed(i64, -2) == 0); + try expect(signed(i64, -1) == 1); + try expect(signed(i64, 0) == 2); + try expect(signed(i64, 1) == 3); + try expect(signed(i64, minInt(i64)) == 4); + try expect(signed(i64, -(1 << 32) - 2) == 4); + try expect(signed(i64, (1 << 32) + 1) == 4); + + try expect(unsigned(u128, 0) == 0); + try expect(unsigned(u128, 1) == 1); + try expect(unsigned(u128, 2) == 2); + try expect(unsigned(u128, 3) == 3); + try expect(unsigned(u128, maxInt(u128)) == 4); + try expect(unsigned(u128, (1 << 64) + 1) == 4); + + try expect(signed(i128, -2) == 0); + try expect(signed(i128, -1) == 1); + try expect(signed(i128, 0) == 2); + try expect(signed(i128, 1) == 3); + try expect(signed(i128, minInt(i128)) == 4); + try expect(signed(i128, -(1 << 64) - 2) == 4); + try expect(signed(i128, (1 << 64) + 1) == 4); + + try expect(unsigned(u999, 0) == 0); + try expect(unsigned(u999, 1) == 1); + try expect(unsigned(u999, 2) == 2); + try expect(unsigned(u999, 3) == 3); + try expect(unsigned(u999, maxInt(u999)) == 4); + try expect(unsigned(u999, (1 << 499) + 1) == 4); + + try expect(signed(i999, -2) == 0); + try expect(signed(i999, -1) == 1); + try expect(signed(i999, 0) == 2); + try expect(signed(i999, 1) == 3); + try expect(signed(i999, minInt(i999)) == 4); + try expect(signed(i999, -(1 << 499) - 2) == 4); + try expect(signed(i999, (1 << 499) + 1) == 4); + } }; + + try S.doTheTest(); + try comptime S.doTheTest(); } test "implicit comptime switch" { -- 2.54.0 From 29c18b40dcb74789ed054e9fe599a4a8f644b08e Mon Sep 17 00:00:00 2001 From: Pavel Verigo Date: Sat, 17 Oct 2026 23:39:40 +0200 Subject: [PATCH 4/6] wasm: implement static archive --- src/codegen/wasm/Emit.zig | 4 +- src/link/Wasm.zig | 91 ++++++++++++------------- src/link/Wasm/Archive.zig | 138 ++++++++++++++++++++++++++++++++++++++ src/link/Wasm/Flush.zig | 31 +++++++-- 4 files changed, 213 insertions(+), 51 deletions(-) diff --git a/src/codegen/wasm/Emit.zig b/src/codegen/wasm/Emit.zig index 6193650464133168e21379e8cf810d8fb9e9ac12..2a39fed32ef4447f2e7d16ce3eb90062bb667cd5 100644 --- a/src/codegen/wasm/Emit.zig +++ b/src/codegen/wasm/Emit.zig @@ -27,7 +27,7 @@ pub fn lower(emit: *Emit) Error!void { const wasm = emit.wasm; const comp = wasm.base.comp; const gpa = comp.gpa; - const is_obj = comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); const target = &comp.root_mod.resolved_target.result; const is_wasm32 = target.cpu.arch == .wasm32; @@ -1028,7 +1028,7 @@ fn navRefOff(wasm: *Wasm, code: *ArrayList(u8), data: Mir.NavRefOff, is_wasm32: const zcu = comp.zcu.?; const ip = &zcu.intern_pool; const gpa = comp.gpa; - const is_obj = comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); const nav_ty = ip.getNav(data.nav_index).resolved.?.type; assert(!ip.isFunctionType(nav_ty)); diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 6e77b0f1f8a251c11b1027ce442ed15971711613..24e706478b7e3769a610c81d4b148d24d8b6a72d 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -79,6 +79,7 @@ growable_table: bool, name: []const u8, /// List of relocatable files to be linked into the final binary. objects: std.ArrayList(Object) = .empty, +archive_builder: Archive.Builder = .{}, func_types: std.array_hash_map.Auto(FunctionType, void) = .empty, /// Provides a mapping of both imports and provided functions to symbol name. @@ -467,8 +468,7 @@ pub const OutputDataIndex = enum(u32) { } pub fn fromUav(wasm: *const Wasm, ip_index: InternPool.Index) OutputDataIndex { - const comp = wasm.base.comp; - const resolution: ObjectDataImport.Resolution = if (comp.config.output_mode == .Obj) + const resolution: ObjectDataImport.Resolution = if (wasm.base.isRelocatable()) .pack(wasm, .{ .uav_obj = @fromBackingInt(@intCast(wasm.uavs_obj.getIndex(ip_index).?)) }) else .pack(wasm, .{ .uav_exe = @fromBackingInt(@intCast(wasm.uavs_exe.getIndex(ip_index).?)) }); @@ -482,7 +482,7 @@ pub const OutputDataIndex = enum(u32) { if (nav.getExtern(ip) != null) { return fromSymbolName(wasm, wasm.imports.get(nav_index).?); } - const resolution: ObjectDataImport.Resolution = if (wasm.base.comp.config.output_mode == .Obj) + const resolution: ObjectDataImport.Resolution = if (wasm.base.isRelocatable()) .pack(wasm, .{ .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(nav_index).?)) }) else .pack(wasm, .{ .nav_exe = @fromBackingInt(@intCast(wasm.navs_exe.getIndex(nav_index).?)) }); @@ -500,7 +500,7 @@ pub const GlobalIndex = enum(u32) { /// Same as `stack_pointer` but with a safety assertion. pub fn stackPointer(wasm: *const Wasm) ObjectGlobal.Index { const comp = wasm.base.comp; - assert(comp.config.output_mode != .Obj); + assert(!wasm.base.isRelocatable()); assert(comp.zcu != null); return .stack_pointer; } @@ -879,8 +879,7 @@ const ZcuDataStarts = struct { uavs_i: u32, fn init(wasm: *const Wasm) ZcuDataStarts { - const comp = wasm.base.comp; - const is_obj = comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); return if (is_obj) initObj(wasm) else initExe(wasm); } @@ -897,8 +896,7 @@ const ZcuDataStarts = struct { } fn finish(zds: ZcuDataStarts, wasm: *Wasm, pt: Zcu.PerThread) !void { - const comp = wasm.base.comp; - const is_obj = comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); return if (is_obj) finishObj(zds, wasm, pt) else finishExe(zds, wasm, pt); } @@ -1276,8 +1274,7 @@ pub const GlobalImport = extern struct { const object_global_index = i - first_object_global; if (object_global_index < wasm.object_globals.items.len) return .{ .object_global = @fromBackingInt(@intCast(object_global_index)) }; - const comp = wasm.base.comp; - const is_obj = comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); const uav_index = object_global_index - wasm.object_globals.items.len; if (is_obj) { if (uav_index < wasm.uavs_obj.entries.len) { @@ -1323,7 +1320,7 @@ pub const GlobalImport = extern struct { } pub fn fromIpIndex(wasm: *const Wasm, ip_index: InternPool.Index) Resolution { - const is_obj = wasm.base.comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); return pack(wasm, if (is_obj) .{ .uav_obj = @fromBackingInt(@intCast(wasm.uavs_obj.getIndex(ip_index).?)), } else .{ @@ -1332,8 +1329,7 @@ pub const GlobalImport = extern struct { } pub fn fromIpNav(wasm: *const Wasm, ip_nav: InternPool.Nav.Index) Resolution { - const comp = wasm.base.comp; - const is_obj = comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); return pack(wasm, if (is_obj) .{ .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(ip_nav).?)), } else .{ @@ -1819,8 +1815,7 @@ pub const ObjectDataImport = extern struct { else object_index - wasm.object_datas.items.len; - const comp = wasm.base.comp; - const is_obj = comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); if (is_obj) { const nav_index = if (uav_index < wasm.uavs_obj.entries.len) return .{ .uav_obj = @fromBackingInt(@intCast(uav_index)) } @@ -1863,7 +1858,7 @@ pub const ObjectDataImport = extern struct { } pub fn fromIpIndex(wasm: *const Wasm, ip_index: InternPool.Index) Resolution { - const is_obj = wasm.base.comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); return pack(wasm, if (is_obj) .{ .uav_obj = @fromBackingInt(@intCast(wasm.uavs_obj.getIndex(ip_index).?)), } else .{ @@ -1872,7 +1867,7 @@ pub const ObjectDataImport = extern struct { } pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) Resolution { - const is_obj = wasm.base.comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); return pack(wasm, if (is_obj) .{ .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(nav_index).?)), } else .{ @@ -2117,8 +2112,7 @@ pub const DataSegmentId = enum(u32) { else object_index - wasm.object_data_segments.items.len; - const comp = wasm.base.comp; - const is_obj = comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); if (is_obj) { const nav_index = if (uav_index < wasm.uavs_obj.entries.len) return .{ .uav_obj = @fromBackingInt(@intCast(uav_index)) } @@ -2139,8 +2133,7 @@ pub const DataSegmentId = enum(u32) { } pub fn fromNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) DataSegmentId { - const comp = wasm.base.comp; - const is_obj = comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); return pack(wasm, if (is_obj) .{ .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(nav_index).?)), } else .{ @@ -2717,7 +2710,7 @@ pub const FunctionImportId = enum(u32) { /// Asserts not emitting an object, and `Wasm.import_symbols` is false. pub fn undefinedAllowed(id: FunctionImportId, wasm: *const Wasm) bool { assert(!wasm.import_symbols); - assert(wasm.base.comp.config.output_mode != .Obj); + assert(!wasm.base.isRelocatable()); return switch (unpack(id, wasm)) { .object_function_import => |i| { const import = i.value(wasm); @@ -3343,6 +3336,7 @@ pub fn createEmpty( assert(target.ofmt == .wasm); const output_mode = comp.config.output_mode; + const is_relocatable = output_mode == .Obj or (output_mode == .Lib and comp.config.link_mode == .static); const wasi_exec_model = comp.config.wasi_exec_model; const wasm = try arena.create(Wasm); @@ -3356,7 +3350,7 @@ pub fn createEmpty( // majority of cases, and therefore express "no garbage collection" // in terms of setting the no_strip and must_link flags on all // symbols. - .gc_sections = options.gc_sections orelse (output_mode != .Obj), + .gc_sections = options.gc_sections orelse !is_relocatable, .print_gc_sections = options.print_gc_sections, .stack_size = options.stack_size orelse switch (target.os.tag) { .freestanding => 1 * 1024 * 1024, // 1 MiB @@ -3436,6 +3430,11 @@ fn parseObject(wasm: *Wasm, obj: link.Input.Object) !void { }; if (n != file_contents.len) return error.UnexpectedEndOfFile; + if (wasm.base.isStaticLib()) { + try wasm.archive_builder.append(gpa, std.fs.path.basename(obj.path.sub_path), file_contents); + return; + } + var ss: Object.ScratchSpace = .{}; defer ss.deinit(gpa); @@ -3526,6 +3525,7 @@ pub fn deinit(wasm: *Wasm) void { wasm.object_relocations_table.deinit(gpa); wasm.object_comdat_symbols.deinit(gpa); wasm.objects.deinit(gpa); + wasm.archive_builder.deinit(gpa); wasm.func_types.deinit(gpa); wasm.function_exports.deinit(gpa); @@ -3575,7 +3575,7 @@ pub fn updateFunc( const zcu = pt.zcu; const gpa = zcu.gpa; const ip = &zcu.intern_pool; - const is_obj = zcu.comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); const target = &zcu.comp.root_mod.resolved_target.result; const owner_nav = zcu.funcInfo(func_index).owner_nav; log.debug("updateFunc {f}", .{ip.getNav(owner_nav).fqn.fmt(ip)}); @@ -3656,7 +3656,7 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index const nav = ip.getNav(nav_index); const comp = wasm.base.comp; const gpa = comp.gpa; - const is_obj = comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); const target = &comp.root_mod.resolved_target.result; switch (ip.indexToKey(nav.resolved.?.value)) { @@ -3740,7 +3740,7 @@ pub fn updateExports( const zcu = pt.zcu; const gpa = zcu.gpa; const ip = &zcu.intern_pool; - const is_obj = wasm.base.comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); for (export_indices) |export_idx| { const exp = export_idx.ptr(zcu); @@ -3797,7 +3797,11 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void { .dso => unreachable, .tbd => unreachable, .object => |obj| try parseObject(wasm, obj), - .archive => |obj| try parseArchive(wasm, obj), + .archive => |obj| if (wasm.base.isStaticLib()) { + obj.file.close(io); // ignore archives like LLVM + } else { + try parseArchive(wasm, obj); + }, } } @@ -3811,7 +3815,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.Error!void { const comp = wasm.base.comp; const gpa = comp.gpa; const rdynamic = comp.config.rdynamic; - const is_obj = comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); assert(wasm.missing_exports.entries.len == 0); for (wasm.export_symbol_names) |exp_name| { @@ -3915,7 +3919,7 @@ pub fn markFunctionImport( const comp = wasm.base.comp; const gpa = comp.gpa; - const is_obj = comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); try wasm.functions.ensureUnusedCapacity(gpa, 1); @@ -3949,7 +3953,7 @@ fn markFunction(wasm: *Wasm, i: ObjectFunctionIndex, override_export: bool) link if (gop.found_existing) return; const rdynamic = comp.config.rdynamic; - const is_obj = comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); const function = i.ptr(wasm); try markObject(wasm, function.object_index); @@ -3991,7 +3995,7 @@ fn markGlobalImport( const comp = wasm.base.comp; const gpa = comp.gpa; - const is_obj = comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); try wasm.globals.ensureUnusedCapacity(gpa, 1); @@ -4034,7 +4038,7 @@ fn markGlobal(wasm: *Wasm, i: ObjectGlobalIndex, override_export: bool) link.Err if (gop.found_existing) return; const rdynamic = comp.config.rdynamic; - const is_obj = comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); const global = i.ptr(wasm); try markObject(wasm, global.object_index); @@ -4057,7 +4061,7 @@ pub fn markTableImport( const comp = wasm.base.comp; const gpa = comp.gpa; - const is_obj = comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); try wasm.tables.ensureUnusedCapacity(gpa, 1); @@ -4103,7 +4107,7 @@ pub fn markDataImport( const comp = wasm.base.comp; const gpa = comp.gpa; - const is_obj = comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); if (import.resolution == .unresolved) { if (!is_obj) { @@ -4682,7 +4686,7 @@ pub fn addNavReloc( const ip = &zcu.intern_pool; const gpa = comp.gpa; - const is_obj = comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); if (nav_ty.zigTypeTag(zcu) == .@"fn") { const gop = try wasm.zcu_indirect_function_set.getOrPut(gpa, nav_index); @@ -4751,7 +4755,7 @@ pub fn addUavReloc( gop.value_ptr.* = if (gop.found_existing) gop.value_ptr.maxStrict(this_align) else this_align; } - if (comp.config.output_mode == .Obj) { + if (wasm.base.isRelocatable()) { const gop = try wasm.uavs_obj.getOrPut(gpa, uav_val); if (!gop.found_existing) gop.value_ptr.* = undefined; // to avoid recursion, `ZcuDataStarts` will lower the value later try wasm.zcu_relocations.append(gpa, .{ @@ -4782,7 +4786,7 @@ pub fn addUavReloc( pub fn refNavObj(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsObjIndex { const comp = wasm.base.comp; const gpa = comp.gpa; - assert(comp.config.output_mode == .Obj); + assert(wasm.base.isRelocatable()); const gop = try wasm.navs_obj.getOrPut(gpa, nav_index); if (!gop.found_existing) gop.value_ptr.* = .{ // Lowering the value is delayed to avoid recursion. @@ -4795,7 +4799,7 @@ pub fn refNavObj(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsObjIndex { pub fn refNavExe(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsExeIndex { const comp = wasm.base.comp; const gpa = comp.gpa; - assert(comp.config.output_mode != .Obj); + assert(!wasm.base.isRelocatable()); const gop = try wasm.navs_exe.getOrPut(gpa, nav_index); if (gop.found_existing) { gop.value_ptr.count += 1; @@ -4812,8 +4816,7 @@ pub fn refNavExe(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsExeIndex { /// Asserts it is called after `Flush.data_segments` is fully populated and sorted. pub fn uavAddr(wasm: *const Wasm, ip_index: InternPool.Index) u32 { assert(wasm.flush_buffer.memory_layout_finished); - const comp = wasm.base.comp; - assert(comp.config.output_mode != .Obj); + assert(!wasm.base.isRelocatable()); const uav_index: UavsExeIndex = @fromBackingInt(@intCast(wasm.uavs_exe.getIndex(ip_index).?)); const ds_id: DataSegmentId = .pack(wasm, .{ .uav_exe = uav_index }); return wasm.flush_buffer.data_segments.get(ds_id).?; @@ -4834,7 +4837,7 @@ pub fn syntheticDataAddr(wasm: *const Wasm, resolution: ObjectDataImport.Resolut pub fn navAddr(wasm: *const Wasm, nav_index: InternPool.Nav.Index) u32 { assert(wasm.flush_buffer.memory_layout_finished); const comp = wasm.base.comp; - assert(comp.config.output_mode != .Obj); + assert(!wasm.base.isRelocatable()); if (wasm.navs_exe.getIndex(nav_index)) |i| { const navs_exe_index: NavsExeIndex = @fromBackingInt(@intCast(i)); log.debug("navAddr {s} {}", .{ navs_exe_index.name(wasm), nav_index }); @@ -4888,15 +4891,13 @@ pub fn navAddr(wasm: *const Wasm, nav_index: InternPool.Nav.Index) u32 { /// Asserts it is called after `Flush.data_segments` is fully populated and sorted. pub fn errorNameTableAddr(wasm: *Wasm) u32 { assert(wasm.flush_buffer.memory_layout_finished); - const comp = wasm.base.comp; - assert(comp.config.output_mode != .Obj); + assert(!wasm.base.isRelocatable()); return wasm.flush_buffer.data_segments.get(.__zig_error_name_table).?; } pub fn tagIndexTableAddr(wasm: *Wasm, ip_index: InternPool.Index) u32 { assert(wasm.flush_buffer.memory_layout_finished); - const comp = wasm.base.comp; - assert(comp.config.output_mode != .Obj); + assert(!wasm.base.isRelocatable()); const f = &wasm.flush_buffer; const table_base_addr = f.data_segments.get(.__zig_tag_name_table).?; return table_base_addr + wasm.tagIndexTableOffset(ip_index); diff --git a/src/link/Wasm/Archive.zig b/src/link/Wasm/Archive.zig index 48665264f3cab69532a8e70d371fe506578d3ea8..37d9bda33ca039bb54aad55327acb5ced957be5f 100644 --- a/src/link/Wasm/Archive.zig +++ b/src/link/Wasm/Archive.zig @@ -68,6 +68,143 @@ const Header = extern struct { } }; +pub const Builder = struct { + file_names: std.ArrayList(u8) = .empty, + members: std.ArrayList(u8) = .empty, + symbol_names: std.ArrayList(u8) = .empty, + symbol_offsets: std.ArrayList(u32) = .empty, + + pub fn deinit(b: *Builder, gpa: Allocator) void { + b.file_names.deinit(gpa); + b.members.deinit(gpa); + b.symbol_names.deinit(gpa); + b.symbol_offsets.deinit(gpa); + b.* = undefined; + } + + pub fn append(b: *Builder, gpa: Allocator, name: []const u8, data: []const u8) !void { + const member_offset: u32 = @intCast(b.members.items.len); + const name_offset = b.file_names.items.len; + + try b.file_names.appendSlice(gpa, name); + try b.file_names.appendSlice(gpa, "/\n"); + + var name_buf: [16]u8 = undefined; + const header_name = try std.mem.print(&name_buf, "/{d}", .{name_offset}); + const member_size = @sizeOf(Header) + mem.alignForward(usize, data.len, 2); + var w: std.Io.Writer = .fixed(try b.members.addManyAsSlice(gpa, member_size)); + try writeHeader(&w, header_name, data.len); + try w.writeAll(data); + if (data.len % 2 != 0) try w.writeByte('\n'); + + try b.collectSymbols(gpa, data, member_offset); + } + + pub fn write(b: *Builder, w: *std.Io.Writer) std.Io.Writer.Error!void { + const symtab_size = 4 + 4 * b.symbol_offsets.items.len + b.symbol_names.items.len; + const members_offset = ARMAG.len + @sizeOf(Header) + mem.alignForward(usize, symtab_size, 2) + + @sizeOf(Header) + mem.alignForward(usize, b.file_names.items.len, 2); + + try w.writeAll(ARMAG); + + try writeHeader(w, "/", symtab_size); + try w.writeInt(u32, @intCast(b.symbol_offsets.items.len), .big); + for (b.symbol_offsets.items) |offset| try w.writeInt(u32, @intCast(members_offset + offset), .big); + try w.writeAll(b.symbol_names.items); + if (symtab_size % 2 != 0) try w.writeByte('\n'); + + try writeHeader(w, "//", b.file_names.items.len); + try w.writeAll(b.file_names.items); + if (b.file_names.items.len % 2 != 0) try w.writeByte('\n'); + + try w.writeAll(b.members.items); + } + + fn collectSymbols(b: *Builder, gpa: Allocator, data: []const u8, member_offset: u32) !void { + var reader: std.Io.Reader = .fixed(data); + if (!mem.eql(u8, try reader.take(4), &std.wasm.magic)) return error.BadObjectMagic; + if (!mem.eql(u8, try reader.take(4), &std.wasm.version)) return error.UnsupportedVersion; + + while (reader.seek < data.len) { + const section_tag = try reader.takeEnum(std.wasm.Section, .little); + const section_len = try reader.takeLeb128(u32); + var section: std.Io.Reader = .fixed(try reader.take(section_len)); + if (section_tag != .custom) continue; + + const section_name = try readBytes(§ion); + if (mem.eql(u8, section_name, "linking")) { + const section_version = try section.takeLeb128(u32); + if (section_version != 2) return error.UnsupportedVersion; + + while (section.seek < section.buffer.len) { + const sub_type = try section.takeLeb128(u8); + const payload_len = try section.takeLeb128(u32); + + var symtab: std.Io.Reader = .fixed(try section.take(payload_len)); + if (sub_type != @backingInt(Object.SubsectionType.symbol_table)) continue; + + const count = try symtab.takeLeb128(u32); + for (0..count) |_| { + const tag = try symtab.takeEnum(Object.Symbol.Tag, .little); + const flags = try symtab.takeLeb128(u32); + const symbol_flags: Wasm.SymbolFlags = @bitCast(flags); + + var name: []const u8 = undefined; + switch (tag) { + .data => { + name = try readBytes(&symtab); + if (!symbol_flags.undefined) { + _ = try symtab.takeLeb128(u32); + _ = try symtab.takeLeb128(u64); + _ = try symtab.takeLeb128(u64); + } + }, + .section => { + _ = try symtab.takeLeb128(u32); + continue; + }, + .function, .global, .event, .table => { + _ = try symtab.takeLeb128(u32); + if (!symbol_flags.undefined or symbol_flags.explicit_name) { + name = try readBytes(&symtab); + } + }, + } + + if (!symbol_flags.undefined and symbol_flags.binding != .local) { + try b.symbol_names.appendSlice(gpa, name); + try b.symbol_names.append(gpa, 0); + try b.symbol_offsets.append(gpa, member_offset); + } + } + } + return; + } + } + return error.MissingLinkingSection; + } +}; + +fn writeHeader(w: *std.Io.Writer, name: []const u8, size: usize) std.Io.Writer.Error!void { + var header: Header = .{ + .name = @splat(' '), + .date = "0 ".*, + .uid = "0 ".*, + .gid = "0 ".*, + .mode = "644 ".*, + .size = @splat(' '), + .fmag = ARFMAG.*, + }; + @memcpy(header.name[0..name.len], name); + _ = std.mem.print(&header.size, "{d}", .{size}) catch unreachable; + try w.writeAll(mem.asBytes(&header)); +} + +fn readBytes(reader: *std.Io.Reader) ![]const u8 { + const len = try reader.takeLeb128(u32); + return reader.take(len); +} + pub fn deinit(archive: *Archive, gpa: Allocator) void { deinitToc(gpa, &archive.toc); archive.* = undefined; @@ -102,6 +239,7 @@ pub fn parse(gpa: Allocator, file_contents: []const u8) !Archive { const sym_tab = file_contents[pos..][0 .. sym_tab_size - 4 - symbol_positions_size]; pos += sym_tab.len; + pos = mem.alignForward(usize, pos, 2); var toc: Toc = .empty; errdefer deinitToc(gpa, &toc); diff --git a/src/link/Wasm/Flush.zig b/src/link/Wasm/Flush.zig index 745e3023dc0a9e61e68f7f6164c6ed220915447f..00ad4ef87ae0beabd19a9256d3a09318aac7923f 100644 --- a/src/link/Wasm/Flush.zig +++ b/src/link/Wasm/Flush.zig @@ -247,7 +247,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { .wasm64 => true, else => unreachable, }; - const is_obj = comp.config.output_mode == .Obj; + const is_obj = wasm.base.isRelocatable(); const allow_undefined = is_obj or wasm.import_symbols; const zcu_references = if (comp.zcu) |zcu| try zcu.resolveReferences() else null; @@ -1725,9 +1725,32 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { // Finally, write the entire binary into the file. var file_writer = wasm.base.file.?.writer(io, &.{}); - file_writer.interface.writeAll(binary_bytes.items) catch |err| switch (err) { - error.WriteFailed => return file_writer.err.?, - }; + if (wasm.base.isStaticLib()) { + const builder = &wasm.archive_builder; + // restore for incremental + const file_names_len = builder.file_names.items.len; + defer builder.file_names.shrinkRetainingCapacity(file_names_len); + const members_len = builder.members.items.len; + defer builder.members.shrinkRetainingCapacity(members_len); + const symbol_names_len = builder.symbol_names.items.len; + defer builder.symbol_names.shrinkRetainingCapacity(symbol_names_len); + const symbol_offsets_len = builder.symbol_offsets.items.len; + defer builder.symbol_offsets.shrinkRetainingCapacity(symbol_offsets_len); + + // TODO: pass ZCU data and symbols to write, so reparsing not needed + if (comp.zcu != null) { + const name = try std.fmt.allocPrint(gpa, "{s}_zcu.o", .{comp.root_name}); + defer gpa.free(name); + try builder.append(gpa, name, binary_bytes.items); + } + builder.write(&file_writer.interface) catch |err| switch (err) { + error.WriteFailed => return file_writer.err.?, + }; + } else { + file_writer.interface.writeAll(binary_bytes.items) catch |err| switch (err) { + error.WriteFailed => return file_writer.err.?, + }; + } file_writer.end() catch |err| switch (err) { error.WriteFailed => return file_writer.err.?, else => |e| return e, -- 2.54.0 From 151597cc0dcfcad384218a2b92cae4b23b11ebe6 Mon Sep 17 00:00:00 2001 From: Pavel Verigo Date: Sun, 18 Oct 2026 18:29:34 +0200 Subject: [PATCH 5/6] x86_64: fix repr of ?error --- src/codegen/x86_64/CodeGen.zig | 20 +++++++++----------- test/behavior/optional.zig | 1 + 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/codegen/x86_64/CodeGen.zig b/src/codegen/x86_64/CodeGen.zig index 4f9b9ef0b0a2c6d3df51f642256e83b7cdda8a24..c6bf1686697b9f910ab279f41a20dcb0c02a2e74 100644 --- a/src/codegen/x86_64/CodeGen.zig +++ b/src/codegen/x86_64/CodeGen.zig @@ -181803,17 +181803,15 @@ fn intInfo(cg: *CodeGen, ty: Type) ?std.lang.Type.Int { .one, .many, .c => .{ .signedness = .unsigned, .bits = cg.target.ptrBitWidth() }, .slice => null, }, - .opt_type => |opt_child| return if (!Type.fromInterned(opt_child).hasRuntimeBits(zcu)) - .{ .signedness = .unsigned, .bits = 1 } - else switch (ip.indexToKey(opt_child)) { - .ptr_type => |ptr_type| switch (ptr_type.flags.size) { - .one, .many => switch (ptr_type.flags.is_allowzero) { - false => .{ .signedness = .unsigned, .bits = cg.target.ptrBitWidth() }, - true => null, - }, - .slice, .c => null, - }, - else => null, + .opt_type => |opt_child| { + if (!Type.fromInterned(opt_child).hasRuntimeBits(zcu)) { + return .{ .signedness = .unsigned, .bits = 1 }; + } + if (Type.fromInterned(ty_index).optionalReprIsPayload(zcu)) { + ty_index = opt_child; + continue; + } + return null; }, .error_union_type => |error_union_type| return if (!Type.fromInterned(error_union_type.payload_type) .hasRuntimeBits(zcu)) .{ .signedness = .unsigned, .bits = zcu.errorSetBits() } else null, diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig index f8e36204603a2eb991c13eaa4fd3e4c8e0406018..f19877ab5c151db2d3d82532bb59c75c961a5e56 100644 --- a/test/behavior/optional.zig +++ b/test/behavior/optional.zig @@ -59,6 +59,7 @@ fn testNullPtrsEql() !void { } test "optional error equality" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; -- 2.54.0 From 72f3d3aeea07c5b16fb97c789b898f18e05eda9e Mon Sep 17 00:00:00 2001 From: Pavel Verigo Date: Tue, 20 Oct 2026 03:52:17 +0200 Subject: [PATCH 6/6] wasm: no pt in CodeGen --- src/codegen/wasm/CodeGen.zig | 254 +++++++++++++++++------------------ 1 file changed, 123 insertions(+), 131 deletions(-) diff --git a/src/codegen/wasm/CodeGen.zig b/src/codegen/wasm/CodeGen.zig index 90da3698142b255453c955a95b1b2af91ca39a79..6f3c218e58ab44b2fb0c99a9a905014d85801ab9 100644 --- a/src/codegen/wasm/CodeGen.zig +++ b/src/codegen/wasm/CodeGen.zig @@ -157,7 +157,7 @@ simd_immediates: std.ArrayList([16]u8) = .empty, /// The Target we're emitting (used to call intInfo) target: *const std.Target, ptr_size: enum { wasm32, wasm64 }, -pt: Zcu.PerThread, +zcu: *Zcu, /// List of MIR Instructions mir_instructions: std.MultiArrayList(Mir.Inst), /// Contains extra data for MIR @@ -380,7 +380,7 @@ pub fn deinit(cg: *CodeGen) void { } pub fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) Error { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const func = zcu.funcInfo(cg.func_index); return zcu.codegenFail(func.owner_nav, fmt, args); } @@ -395,8 +395,7 @@ fn resolveInst(cg: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue { const gop = try cg.values.getOrPut(cg.gpa, ref); assert(!gop.found_existing); - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const val: Value = .fromInterned(ref.toInterned().?); const ty = cg.typeOf(ref); if (!ty.hasRuntimeBits(zcu) and !ty.isInt(zcu) and !ty.isError(zcu)) { @@ -420,7 +419,7 @@ fn resolveInst(cg: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue { } fn resolveValue(cg: *CodeGen, val: Value) InnerError!WValue { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty = val.typeOf(zcu); return if (isByRef(ty, zcu, cg.target)) @@ -761,7 +760,7 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void { .float32 => |val| try cg.addFloat32(val), .float64 => |val| try cg.addFloat64(val), .nav_ref => |nav_ref| { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ip = &zcu.intern_pool; if (ip.zigTypeTag(ip.getNav(nav_ref.nav_index).resolved.?.type) == .@"fn") { assert(nav_ref.offset == 0); @@ -782,7 +781,7 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void { } }, .uav_ref => |uav| { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ip = &zcu.intern_pool; assert(!ip.isFunctionType(ip.typeOf(uav.ip_index))); const gop = try cg.mir_uavs.getOrPut(cg.gpa, uav.ip_index); @@ -853,7 +852,7 @@ fn releaseLocal(cg: *CodeGen, index: u32) void { /// Creates one locals for a given `Type`. /// Returns a corresponding `Wvalue` with `local` as active tag fn allocLocal(cg: *CodeGen, ty: Type) InnerError!WValue { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const valtype = typeToValtype(ty, zcu, cg.target); const free_list = cg.local_pool.freeList(valtype); if (free_list.unwrap()) |index| { @@ -870,7 +869,7 @@ fn allocLocal(cg: *CodeGen, ty: Type) InnerError!WValue { /// Ensures a new local will be created. This is useful when it's useful /// to use a zero-initialized local. fn ensureAllocLocal(cg: *CodeGen, ty: Type) InnerError!WValue { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; try cg.mir_locals.ensureUnusedCapacity(cg.gpa, 1); try cg.local_pool.locals.ensureUnusedCapacity(cg.gpa, 1); assert(cg.mir_locals.items.len == cg.local_pool.locals.items.len); @@ -905,7 +904,7 @@ pub fn generate( var code_gen: CodeGen = .{ .gpa = gpa, - .pt = pt, + .zcu = zcu, .air = air.*, .liveness = liveness.*.?, .owner_nav = cg.owner_nav, @@ -940,7 +939,7 @@ pub fn generate( } fn generateInner(cg: *CodeGen, any_returns: bool) InnerError!Mir { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; cg.wasm_param_count = @intCast(cg.args.len + @intFromBool(cg.return_value != .none) + @intFromBool(cg.varargs != .none)); cg.initial_stack_value = try cg.ensureAllocLocal(Type.usize); cg.bottom_stack_value = try cg.ensureAllocLocal(Type.usize); @@ -1099,7 +1098,7 @@ fn lowerArg(cg: *CodeGen, cc: std.lang.CallingConvention, ty: Type, value: WValu return cg.emitWValue(value); } - const zcu = cg.pt.zcu; + const zcu = cg.zcu; switch (abi.classifyType(ty, zcu, cg.target)) { .direct => |scalar_ty| { @@ -1148,8 +1147,7 @@ fn restoreStackPointer(cg: *CodeGen) !void { /// /// Asserts Type has codegenbits fn allocStack(cg: *CodeGen, ty: Type) !WValue { - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; assert(ty.hasRuntimeBits(zcu)); const abi_size = std.math.cast(u32, ty.abiSize(zcu)) orelse { @@ -1187,8 +1185,7 @@ fn allocStackBytes(cg: *CodeGen, size: u32, alignment: Alignment) !WValue { /// This is different from allocStack where this will use the pointer's alignment /// if it is set, to ensure the stack alignment will be set correctly. fn allocStackPtr(cg: *CodeGen, inst: Air.Inst.Index) !WValue { - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const ptr_ty = cg.typeOfIndex(inst); const pointee_ty = ptr_ty.childType(zcu); @@ -1356,7 +1353,7 @@ pub fn determineSimdStoreStrategy(ty: Type, zcu: *const Zcu, target: *const std. } fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const air_tags = cg.air.instructions.items(.tag); return switch (air_tags[@backingInt(inst)]) { // No soft float legalizations are enabled. @@ -1492,7 +1489,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const rhs = try cg.resolveInst(bin_op.rhs); const ty = cg.typeOfIndex(inst); - if (ty.zigTypeTag(cg.pt.zcu) == .vector) { + if (ty.zigTypeTag(cg.zcu) == .vector) { return cg.fail("TODO: implement AIR op: mul_add for vectors", .{}); } @@ -1510,7 +1507,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const rhs = try cg.resolveInst(bin_op.rhs); const ty = cg.typeOfIndex(inst); - if (ty.zigTypeTag(cg.pt.zcu) == .vector) { + if (ty.zigTypeTag(cg.zcu) == .vector) { return cg.fail("TODO: implement AIR op: {s} for vectors", .{@tagName(tag)}); } @@ -1555,7 +1552,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { defer res_tmp.free(cg); const result = try cg.allocStack(cg.typeOfIndex(inst)); - const offset: u32 = @intCast(ty.abiSize(cg.pt.zcu)); + const offset: u32 = @intCast(ty.abiSize(cg.zcu)); try cg.store(result, res_tmp, ty, .{}); try cg.store(result, ov_tmp, .u1, .{ .offset = offset }); @@ -1675,7 +1672,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const src_ty = cg.typeOf(ty_op.operand); const dest_ty = cg.typeOfIndex(inst); - if (dest_ty.zigTypeTag(cg.pt.zcu) == .vector) { + if (dest_ty.zigTypeTag(cg.zcu) == .vector) { return cg.fail("TODO: implement AIR op: {s} for vectors", .{@tagName(tag)}); } @@ -1959,7 +1956,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ip = &zcu.intern_pool; for (body) |inst| { @@ -1979,7 +1976,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { } fn airRet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const un_op = cg.air.instructions.items(.data)[@backingInt(inst)].un_op; const operand = try cg.resolveInst(un_op); const fn_info = zcu.typeToFunc(zcu.navValue(cg.owner_nav).typeOf(zcu)).?; @@ -2019,7 +2016,7 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const child_type = cg.typeOfIndex(inst).childType(zcu); const result = result: { @@ -2039,7 +2036,7 @@ fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const un_op = cg.air.instructions.items(.data)[@backingInt(inst)].un_op; const operand = try cg.resolveInst(un_op); const ret_ty = cg.typeOf(un_op).childType(zcu); @@ -2076,8 +2073,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) const args = call.args; const ty = cg.typeOf(call.callee); - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const ip = &zcu.intern_pool; const fn_ty = switch (ty.zigTypeTag(zcu)) { .@"fn" => ty, @@ -2250,7 +2246,7 @@ fn airVaCopy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airVaArg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; const operand = try cg.resolveInst(ty_op.operand); @@ -2322,8 +2318,7 @@ fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airStore(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void { - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op; const lhs = try cg.resolveInst(bin_op.lhs); @@ -2366,8 +2361,7 @@ const MemArg = struct { fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, memarg: MemArg) InnerError!void { assert(!(lhs != .stack and rhs == .stack)); - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const abi_size = ty.abiSize(zcu); if (!ty.hasRuntimeBits(zcu)) return; @@ -2432,8 +2426,7 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, memarg: MemArg) Inner } fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; const operand = try cg.resolveInst(ty_op.operand); const elem_ty = ty_op.ty; @@ -2459,7 +2452,7 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { /// Loads an operand from the linear memory section. /// NOTE: Leaves the value on the stack, if isByRef == false. fn load(cg: *CodeGen, operand: WValue, ty: Type, memarg: MemArg) InnerError!WValue { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const natural_alignment = ty.abiAlignment(zcu); // wasm memory instruction alignment is <= access width @@ -2537,8 +2530,7 @@ fn load(cg: *CodeGen, operand: WValue, ty: Type, memarg: MemArg) InnerError!WVal } fn airArg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const arg_index = cg.arg_index; const arg = cg.args[arg_index]; const cc = zcu.typeToFunc(zcu.navValue(cg.owner_nav).typeOf(zcu)).?.cc; @@ -2590,7 +2582,7 @@ const IntType = struct { // Adapted from x86_64 backend // Differ from Type.intInfo as it treats pointers/booleans/packed/enums/errors as integer fn fromType(cg: *CodeGen, ty: Type) IntType { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ip = &zcu.intern_pool; var ty_index = ty.ip_index; while (true) switch (ip.indexToKey(ty_index)) { @@ -5041,8 +5033,7 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal } fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerError!WValue { - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const ip = &zcu.intern_pool; const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr; const offset: u64 = prev_offset + ptr.byte_offset; @@ -5056,7 +5047,10 @@ fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerErro .{ .uav_ref = .{ .ip_index = uav.val, .offset = @intCast(offset), .orig_ptr_ty = uav.orig_ty } } else .{ .imm32 = @intCast(Type.fromInterned(uav.orig_ty).ptrAlignment(zcu).forward(@as(u32, 0xaaaaaaaa))) }, - .int => return cg.lowerConstant(try pt.intValue(.usize, offset)), + .int => return switch (cg.ptr_size) { + .wasm32 => .{ .imm32 = @intCast(offset) }, + .wasm64 => .{ .imm64 = offset }, + }, .eu_payload => |eu_ptr| try cg.lowerPtr( eu_ptr, offset + codegen.errUnionPayloadOffset( @@ -5095,8 +5089,7 @@ fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerErro /// Asserts that `isByRef` returns `false` for `val.typeOf(zcu)`. fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue { - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const ty = val.typeOf(zcu); assert(!isByRef(ty, zcu, cg.target)); const ip = &zcu.intern_pool; @@ -5154,22 +5147,16 @@ fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue { } }, .err => |err| { - const int = try pt.getErrorValue(err.name); + const int = ip.getErrorValueIfExists(err.name).?; return .{ .imm32 = int }; }, .error_union => |error_union| { - const err_int_ty = try pt.errorIntType(); - const err_val: Value = switch (error_union.val) { - .err_name => |err_name| .fromInterned(try pt.intern(.{ .err = .{ - .ty = ty.errorUnionSet(zcu).toIntern(), - .name = err_name, - } })), - .payload => try pt.intValue(err_int_ty, 0), - }; const payload_type = ty.errorUnionPayload(zcu); if (!payload_type.hasRuntimeBits(zcu)) { - // We use the error type directly as the type. - return cg.lowerConstant(err_val); + return .{ .imm32 = switch (error_union.val) { + .err_name => |err_name| ip.getErrorValueIfExists(err_name).?, + .payload => 0, + } }; } return cg.fail("Wasm TODO: lowerConstant error union with non-zero-bit payload type", .{}); @@ -5233,7 +5220,7 @@ fn storeSimdImmd(cg: *CodeGen, value: [16]u8) !WValue { } fn emitUndefined(cg: *CodeGen, ty: Type) InnerError!WValue { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; switch (ty.zigTypeTag(zcu)) { .vector => return cg.storeSimdImmd(@splat(0xaa)), .bool, .error_set => return .{ .imm32 = 0xaaaaaaaa }, @@ -5276,7 +5263,7 @@ fn airBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, block_ty: Type, body: []const Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; if (block_ty.isNoReturn(zcu)) { assert(cg.liveness.getBlock(inst).deaths.len == 0); @@ -5385,7 +5372,7 @@ fn airCmp(cg: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) Inne const lhs = try cg.resolveInst(bin_op.lhs); const rhs = try cg.resolveInst(bin_op.rhs); const operand_ty = cg.typeOf(bin_op.lhs); - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const type_tag = operand_ty.zigTypeTag(zcu); @@ -5617,10 +5604,10 @@ fn airCmpLteErrorsLen(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const operand = try cg.resolveInst(un_op); try cg.emitWValue(operand); - const pt = cg.pt; - const err_int_ty = try pt.errorIntType(); + const zcu = cg.zcu; + const err_int_ty: IntType = .{ .is_signed = false, .bits = zcu.errorSetBits() }; try cg.addTag(.errors_len); - const result = try cg.intCmp(.fromType(cg, err_int_ty), .lt, .stack, .stack); + const result = try cg.intCmp(err_int_ty, .lt, .stack, .stack); return cg.finishAir(inst, result, &.{un_op}); } @@ -5676,7 +5663,7 @@ fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airNopCast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; const operand_ty = cg.typeOf(ty_op.operand); @@ -5690,7 +5677,7 @@ fn airNopCast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airIntFromPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; const operand_ty = cg.typeOf(ty_op.operand); @@ -5709,7 +5696,7 @@ fn airIntFromPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airUnionFromEnum(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; const union_ty = cg.typeOfIndex(inst); @@ -5741,7 +5728,7 @@ const BitcastClass = union(enum) { }; fn bitcastClass(cg: *CodeGen, ty: Type) BitcastClass { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; return switch (ty.zigTypeTag(zcu)) { .bool, .int, @@ -5759,7 +5746,7 @@ fn bitcastClass(cg: *CodeGen, ty: Type) BitcastClass { fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerError!WValue { if (dest_ty.eql(src_ty)) return operand; - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const src_class = cg.bitcastClass(src_ty); const dest_class = cg.bitcastClass(dest_ty); const src_by_ref = isByRef(src_ty, zcu, cg.target); @@ -5835,7 +5822,7 @@ fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerErro } fn airStructFieldPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl; const extra = cg.air.extraData(Air.StructField, ty_pl.payload); @@ -5847,7 +5834,7 @@ fn airStructFieldPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airStructFieldPtrIndex(cg: *CodeGen, inst: Air.Inst.Index, index: u32) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; const struct_ptr = try cg.resolveInst(ty_op.operand); const struct_ptr_ty = cg.typeOf(ty_op.operand); @@ -5865,8 +5852,7 @@ fn structFieldPtr( struct_ty: Type, index: u32, ) InnerError!WValue { - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const result_ty = cg.typeOfIndex(inst); const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(zcu); @@ -5888,8 +5874,7 @@ fn structFieldPtr( } fn airAggFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl; const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data; @@ -5917,8 +5902,7 @@ fn airAggFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { // Both `.switch_br` and `.loop_switch_br` are noreturn. fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) InnerError!void { - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const switch_br = cg.air.unwrapSwitch(inst); const target_ty = cg.typeOf(switch_br.operand); @@ -6146,7 +6130,7 @@ fn airSwitchDispatch(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kind: enum { value, ptr }) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const un_op = cg.air.instructions.items(.data)[@backingInt(inst)].un_op; const operand = try cg.resolveInst(un_op); const err_union_ty = switch (op_kind) { @@ -6185,7 +6169,7 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kind /// E!T -> T op_is_ptr == false /// *(E!T) -> *T op_is_prt == true fn airUnwrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; const operand = try cg.resolveInst(ty_op.operand); @@ -6217,7 +6201,7 @@ fn airUnwrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) /// *(E!T) -> E op_is_ptr == true /// NOTE: op_is_ptr will not change return type fn airUnwrapErrUnionError(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; const operand = try cg.resolveInst(ty_op.operand); @@ -6242,7 +6226,7 @@ fn airUnwrapErrUnionError(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) I } fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; const operand = try cg.resolveInst(ty_op.operand); @@ -6271,7 +6255,7 @@ fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; const operand = try cg.resolveInst(ty_op.operand); @@ -6311,8 +6295,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kin /// For a given type and operand, checks if it's considered `null`. /// NOTE: Leaves the result on the stack fn isNull(cg: *CodeGen, operand: WValue, op_ty: Type, opcode: std.wasm.Opcode, op_kind: OpKind) InnerError!WValue { - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const optional_ty = switch (op_kind) { .value => op_ty, .ptr => op_ty.childType(zcu), @@ -6357,7 +6340,7 @@ fn isNull(cg: *CodeGen, operand: WValue, op_ty: Type, opcode: std.wasm.Opcode, o } fn airOptionalPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; const opt_ty = cg.typeOf(ty_op.operand); const payload_ty = cg.typeOfIndex(inst); @@ -6379,7 +6362,7 @@ fn airOptionalPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airOptionalPayloadPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; const operand = try cg.resolveInst(ty_op.operand); const opt_ty = cg.typeOf(ty_op.operand).childType(zcu); @@ -6396,8 +6379,7 @@ fn airOptionalPayloadPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airOptionalPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; const operand = try cg.resolveInst(ty_op.operand); const opt_ty = cg.typeOf(ty_op.operand).childType(zcu); @@ -6421,8 +6403,7 @@ fn airOptionalPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; const payload_ty = cg.typeOf(ty_op.operand); - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const result = result: { if (!payload_ty.hasRuntimeBits(zcu)) { @@ -6478,7 +6459,7 @@ fn airSliceLen(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op; const slice_ty = cg.typeOf(bin_op.lhs); @@ -6499,7 +6480,7 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl; const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data; @@ -6534,7 +6515,7 @@ fn sliceLen(cg: *CodeGen, operand: WValue) InnerError!WValue { } fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; const operand = try cg.resolveInst(ty_op.operand); @@ -6554,7 +6535,7 @@ fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op; const ptr_ty = cg.typeOf(bin_op.lhs); @@ -6579,7 +6560,7 @@ fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl; const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data; @@ -6604,7 +6585,7 @@ fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airPtrBinOp(cg: *CodeGen, inst: Air.Inst.Index, op: PointerOffsetOp) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl; const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data; @@ -6623,7 +6604,7 @@ fn airPtrBinOp(cg: *CodeGen, inst: Air.Inst.Index, op: PointerOffsetOp) InnerErr } fn airMemset(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op; const ptr = try cg.resolveInst(bin_op.lhs); @@ -6657,7 +6638,7 @@ fn airMemset(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void { /// this to wasm's memset instruction. When the feature is not present, /// we implement it manually. fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const abi_size = @as(u32, @intCast(elem_ty.abiSize(zcu))); const len_known_neq_0 = switch (len) { .imm32 => |imm| if (imm != 0) true else return, @@ -6774,7 +6755,7 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) } fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op; const array_ty = cg.typeOf(bin_op.lhs); @@ -6828,7 +6809,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; const operand = try cg.resolveInst(ty_op.operand); const ty = cg.typeOfIndex(inst); @@ -6899,8 +6880,7 @@ fn airSelect(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const unwrapped = cg.air.unwrapShuffleOne(zcu, inst); const result_ty = unwrapped.result_ty; @@ -6931,8 +6911,7 @@ fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const unwrapped = cg.air.unwrapShuffleTwo(zcu, inst); const result_ty = unwrapped.result_ty; @@ -7008,8 +6987,7 @@ fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl; const result_ty = cg.typeOfIndex(inst); const len = @as(usize, @intCast(result_ty.arrayLen(zcu))); @@ -7067,9 +7045,10 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { else => { const result = try cg.allocStack(result_ty); for (elements, 0..) |elem, elem_index| { - if (try result_ty.structFieldValueComptime(pt, elem_index) != null) continue; + if (result_ty.structFieldIsComptime(elem_index, zcu)) continue; const elem_ty = result_ty.fieldType(elem_index, zcu); + if (!elem_ty.hasRuntimeBits(zcu)) continue; const field_offset = result_ty.structFieldOffset(elem_index, zcu); const value = try cg.resolveInst(elem); @@ -7089,8 +7068,7 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const ip = &zcu.intern_pool; const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl; const extra = cg.air.extraData(Air.UnionInit, ty_pl.payload).data; @@ -7102,11 +7080,27 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[extra.field_index]); const field_name = ip.loadEnumType(union_obj.enum_tag_type).field_names.get(ip)[extra.field_index]; - const tag_int = blk: { + const tag_int: WValue = blk: { const tag_ty = union_ty.unionTagTypeHypothetical(zcu); const enum_field_index = tag_ty.enumFieldIndex(field_name, zcu).?; - const tag_val = try pt.enumValueFieldIndex(tag_ty, enum_field_index); - break :blk try cg.lowerConstant(tag_val); + const enum_type = ip.loadEnumType(tag_ty.toIntern()); + const int_ty = Type.fromInterned(enum_type.int_tag_type); + const int_bits = int_ty.intInfo(zcu).bits; + if (int_bits > 64) { + return cg.fail("TODO: union tags > 64 bits", .{}); + } + + if (enum_type.field_values.len == 0) { + // Auto-numbered fields. + break :blk switch (int_bits) { + 0...32 => .{ .imm32 = enum_field_index }, + 33...64 => .{ .imm64 = enum_field_index }, + else => unreachable, + }; + } + + const int_value = enum_type.field_values.get(ip)[enum_field_index]; + break :blk try cg.lowerConstant(.fromInterned(int_value)); }; if (layout.payload_size == 0) { if (layout.tag_size == 0) { @@ -7167,8 +7161,7 @@ fn airWasmMemoryGrow(cg: *CodeGen, inst: Air.Inst.Index) !void { } fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op; const un_ty = cg.typeOf(bin_op.lhs).childType(zcu); const tag_ty = cg.typeOf(bin_op.rhs); @@ -7192,7 +7185,7 @@ fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; const un_ty = cg.typeOf(ty_op.operand); @@ -7212,7 +7205,7 @@ fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airErrUnionPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; const err_set_ty = cg.typeOf(ty_op.operand).childType(zcu); @@ -7236,8 +7229,7 @@ fn airErrUnionPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void } fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const pt = cg.pt; - const zcu = pt.zcu; + const zcu = cg.zcu; const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl; const extra = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data; @@ -7276,7 +7268,7 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn sliceOrArrayPtr(cg: *CodeGen, ptr: WValue, ptr_ty: Type) InnerError!WValue { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; if (ptr_ty.isSlice(zcu)) { return cg.slicePtr(ptr); } else { @@ -7285,7 +7277,7 @@ fn sliceOrArrayPtr(cg: *CodeGen, ptr: WValue, ptr_ty: Type) InnerError!WValue { } fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op; const dst = try cg.resolveInst(bin_op.lhs); const dst_ty = cg.typeOf(bin_op.lhs); @@ -7319,7 +7311,7 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airMemmove(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op; const dst = try cg.resolveInst(bin_op.lhs); const dst_ty = cg.typeOf(bin_op.lhs); @@ -7370,9 +7362,9 @@ fn airErrorName(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { // // As the names are global and the slice elements are constant, we do not have // to make a copy of the ptr+value but can point towards them directly. - const pt = cg.pt; + const zcu = cg.zcu; const name_ty = Type.slice_const_u8_sentinel_0; - const abi_size = name_ty.abiSize(pt.zcu); + const abi_size = name_ty.abiSize(zcu); // Lowers to a i32.const or i64.const with the error table memory address. cg.error_name_table_ref_count += 1; @@ -7433,7 +7425,7 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airTryPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const unwrapped_try = cg.air.unwrapTryPtr(inst); const err_union_ptr = try cg.resolveInst(unwrapped_try.error_union_ptr); const body = unwrapped_try.else_body; @@ -7456,7 +7448,7 @@ fn lowerTry( err_union_ty: Type, operand_is_ptr: bool, ) InnerError!WValue { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const branch_liveness = cg.liveness.getCondBr(inst); const pl_ty = err_union_ty.errorUnionPayload(zcu); @@ -7516,7 +7508,7 @@ fn callIntrinsic( args: []const WValue, ) InnerError!WValue { assert(param_types.len == args.len); - const zcu = cg.pt.zcu; + const zcu = cg.zcu; // Always pass over C-ABI @@ -7574,7 +7566,7 @@ fn airIsNamedEnumValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airErrorSetHasValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ip = &zcu.intern_pool; const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; @@ -7661,7 +7653,7 @@ inline fn useAtomicFeature(cg: *const CodeGen) bool { } fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl; const extra = cg.air.extraData(Air.Cmpxchg, ty_pl.payload).data; @@ -7739,7 +7731,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airAtomicLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const atomic_load = cg.air.instructions.items(.data)[@backingInt(inst)].atomic_load; const ptr = try cg.resolveInst(atomic_load.ptr); const ty = cg.typeOfIndex(inst); @@ -7765,7 +7757,7 @@ fn airAtomicLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const pl_op = cg.air.instructions.items(.data)[@backingInt(inst)].pl_op; const extra = cg.air.extraData(Air.AtomicRmw, pl_op.payload).data; @@ -7972,7 +7964,7 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn airAtomicStore(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op; const ptr = try cg.resolveInst(bin_op.lhs); @@ -8008,7 +8000,7 @@ fn airFrameAddress(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { fn airRuntimeNavPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const ty_nav = cg.air.instructions.items(.data)[@backingInt(inst)].ty_nav; - const mod = cg.pt.zcu.navFileScope(cg.owner_nav).mod.?; + const mod = cg.zcu.navFileScope(cg.owner_nav).mod.?; if (mod.single_threaded) { const result: WValue = .{ .nav_ref = .{ .nav_index = ty_nav.nav, @@ -8024,7 +8016,7 @@ fn airAsm(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { const outputs = unwrapped_asm.outputs; const inputs = unwrapped_asm.inputs; - const zcu = cg.pt.zcu; + const zcu = cg.zcu; const output_ty = cg.typeOfIndex(inst); const result: WValue = if (output_ty.hasRuntimeBits(zcu)) @@ -8091,11 +8083,11 @@ fn airAsm(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { } fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; return cg.air.typeOf(inst, &zcu.intern_pool); } fn typeOfIndex(cg: *CodeGen, inst: Air.Inst.Index) Type { - const zcu = cg.pt.zcu; + const zcu = cg.zcu; return cg.air.typeOfIndex(inst, &zcu.intern_pool); } -- 2.54.0