authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-23 03:20:59+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-23 03:20:59+02:00
log70c86e11c4003550375f963db9258b230033309d
tree72d0f76dfb4c1bd7356b09562024570ab517d403
parent27c099a7331ead56e3e47413396b2c1974dee073
parent72f3d3aeea07c5b16fb97c789b898f18e05eda9e

Merge pull request 'wasm: static archive + codegen fixes' (#37308) from pavelverigo/zig:wasm-fix-comp into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/37308 Reviewed-by: Andrew Kelley <andrew@ziglang.org>

13 files changed, 627 insertions(+), 258 deletions(-)

lib/std/Build/Configuration.zig+1-1
...@@ -2565,7 +2565,7 @@ pub const TargetQuery = struct {...@@ -2565,7 +2565,7 @@ pub const TargetQuery = struct {
2565 .cpu = .{2565 .cpu = .{
2566 .arch = cpu_arch,2566 .arch = cpu_arch,
2567 .model = cpu_arch.parseCpuModel(tq.cpu_name.value.?.slice(c)).?,2567 .model = cpu_arch.parseCpuModel(tq.cpu_name.value.?.slice(c)).?,
2568 .features = tq.cpu_features_add.value.?,2568 .features = tq.cpu_features_add.value orelse .empty,
2569 },2569 },
2570 .os = .{2570 .os = .{
2571 .tag = os_tag,2571 .tag = os_tag,
lib/std/atomic.zig+2
...@@ -160,6 +160,8 @@ test Value {...@@ -160,6 +160,8 @@ test Value {
160}160}
161161
162test "Value.swap" {162test "Value.swap" {
163 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
164
163 var x = Value(usize).init(5);165 var x = Value(usize).init(5);
164 try testing.expectEqual(@as(usize, 5), x.swap(10, .seq_cst));166 try testing.expectEqual(@as(usize, 5), x.swap(10, .seq_cst));
165 try testing.expectEqual(@as(usize, 10), x.load(.seq_cst));167 try testing.expectEqual(@as(usize, 10), x.load(.seq_cst));
lib/std/wasm.zig+3-3
...@@ -514,9 +514,9 @@ pub const AtomicsOpcode = enum(u32) {...@@ -514,9 +514,9 @@ pub const AtomicsOpcode = enum(u32) {
514 i64_atomic_rmw32_add_u = 0x24,514 i64_atomic_rmw32_add_u = 0x24,
515 i32_atomic_rmw_sub = 0x25,515 i32_atomic_rmw_sub = 0x25,
516 i64_atomic_rmw_sub = 0x26,516 i64_atomic_rmw_sub = 0x26,
517 i32_atomic_rmw8_sub_u = 0x27A,517 i32_atomic_rmw8_sub_u = 0x27,
518 i32_atomic_rmw16_sub_u = 0x28A,518 i32_atomic_rmw16_sub_u = 0x28,
519 i64_atomic_rmw8_sub_u = 0x29A,519 i64_atomic_rmw8_sub_u = 0x29,
520 i64_atomic_rmw16_sub_u = 0x2A,520 i64_atomic_rmw16_sub_u = 0x2A,
521 i64_atomic_rmw32_sub_u = 0x2B,521 i64_atomic_rmw32_sub_u = 0x2B,
522 i32_atomic_rmw_and = 0x2C,522 i32_atomic_rmw_and = 0x2C,
src/codegen/wasm/CodeGen.zig+216-167
...@@ -157,7 +157,7 @@ simd_immediates: std.ArrayList([16]u8) = .empty,...@@ -157,7 +157,7 @@ simd_immediates: std.ArrayList([16]u8) = .empty,
157/// The Target we're emitting (used to call intInfo)157/// The Target we're emitting (used to call intInfo)
158target: *const std.Target,158target: *const std.Target,
159ptr_size: enum { wasm32, wasm64 },159ptr_size: enum { wasm32, wasm64 },
160pt: Zcu.PerThread,160zcu: *Zcu,
161/// List of MIR Instructions161/// List of MIR Instructions
162mir_instructions: std.MultiArrayList(Mir.Inst),162mir_instructions: std.MultiArrayList(Mir.Inst),
163/// Contains extra data for MIR163/// Contains extra data for MIR
...@@ -380,7 +380,7 @@ pub fn deinit(cg: *CodeGen) void {...@@ -380,7 +380,7 @@ pub fn deinit(cg: *CodeGen) void {
380}380}
381381
382pub fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) Error {382pub fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) Error {
383 const zcu = cg.pt.zcu;383 const zcu = cg.zcu;
384 const func = zcu.funcInfo(cg.func_index);384 const func = zcu.funcInfo(cg.func_index);
385 return zcu.codegenFail(func.owner_nav, fmt, args);385 return zcu.codegenFail(func.owner_nav, fmt, args);
386}386}
...@@ -395,8 +395,7 @@ fn resolveInst(cg: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue {...@@ -395,8 +395,7 @@ fn resolveInst(cg: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue {
395 const gop = try cg.values.getOrPut(cg.gpa, ref);395 const gop = try cg.values.getOrPut(cg.gpa, ref);
396 assert(!gop.found_existing);396 assert(!gop.found_existing);
397397
398 const pt = cg.pt;398 const zcu = cg.zcu;
399 const zcu = pt.zcu;
400 const val: Value = .fromInterned(ref.toInterned().?);399 const val: Value = .fromInterned(ref.toInterned().?);
401 const ty = cg.typeOf(ref);400 const ty = cg.typeOf(ref);
402 if (!ty.hasRuntimeBits(zcu) and !ty.isInt(zcu) and !ty.isError(zcu)) {401 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 {...@@ -420,7 +419,7 @@ fn resolveInst(cg: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue {
420}419}
421420
422fn resolveValue(cg: *CodeGen, val: Value) InnerError!WValue {421fn resolveValue(cg: *CodeGen, val: Value) InnerError!WValue {
423 const zcu = cg.pt.zcu;422 const zcu = cg.zcu;
424 const ty = val.typeOf(zcu);423 const ty = val.typeOf(zcu);
425424
426 return if (isByRef(ty, zcu, cg.target))425 return if (isByRef(ty, zcu, cg.target))
...@@ -761,7 +760,7 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void {...@@ -761,7 +760,7 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void {
761 .float32 => |val| try cg.addFloat32(val),760 .float32 => |val| try cg.addFloat32(val),
762 .float64 => |val| try cg.addFloat64(val),761 .float64 => |val| try cg.addFloat64(val),
763 .nav_ref => |nav_ref| {762 .nav_ref => |nav_ref| {
764 const zcu = cg.pt.zcu;763 const zcu = cg.zcu;
765 const ip = &zcu.intern_pool;764 const ip = &zcu.intern_pool;
766 if (ip.zigTypeTag(ip.getNav(nav_ref.nav_index).resolved.?.type) == .@"fn") {765 if (ip.zigTypeTag(ip.getNav(nav_ref.nav_index).resolved.?.type) == .@"fn") {
767 assert(nav_ref.offset == 0);766 assert(nav_ref.offset == 0);
...@@ -782,7 +781,7 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void {...@@ -782,7 +781,7 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void {
782 }781 }
783 },782 },
784 .uav_ref => |uav| {783 .uav_ref => |uav| {
785 const zcu = cg.pt.zcu;784 const zcu = cg.zcu;
786 const ip = &zcu.intern_pool;785 const ip = &zcu.intern_pool;
787 assert(!ip.isFunctionType(ip.typeOf(uav.ip_index)));786 assert(!ip.isFunctionType(ip.typeOf(uav.ip_index)));
788 const gop = try cg.mir_uavs.getOrPut(cg.gpa, uav.ip_index);787 const gop = try cg.mir_uavs.getOrPut(cg.gpa, uav.ip_index);
...@@ -853,7 +852,7 @@ fn releaseLocal(cg: *CodeGen, index: u32) void {...@@ -853,7 +852,7 @@ fn releaseLocal(cg: *CodeGen, index: u32) void {
853/// Creates one locals for a given `Type`.852/// Creates one locals for a given `Type`.
854/// Returns a corresponding `Wvalue` with `local` as active tag853/// Returns a corresponding `Wvalue` with `local` as active tag
855fn allocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {854fn allocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {
856 const zcu = cg.pt.zcu;855 const zcu = cg.zcu;
857 const valtype = typeToValtype(ty, zcu, cg.target);856 const valtype = typeToValtype(ty, zcu, cg.target);
858 const free_list = cg.local_pool.freeList(valtype);857 const free_list = cg.local_pool.freeList(valtype);
859 if (free_list.unwrap()) |index| {858 if (free_list.unwrap()) |index| {
...@@ -870,7 +869,7 @@ fn allocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {...@@ -870,7 +869,7 @@ fn allocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {
870/// Ensures a new local will be created. This is useful when it's useful869/// Ensures a new local will be created. This is useful when it's useful
871/// to use a zero-initialized local.870/// to use a zero-initialized local.
872fn ensureAllocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {871fn ensureAllocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {
873 const zcu = cg.pt.zcu;872 const zcu = cg.zcu;
874 try cg.mir_locals.ensureUnusedCapacity(cg.gpa, 1);873 try cg.mir_locals.ensureUnusedCapacity(cg.gpa, 1);
875 try cg.local_pool.locals.ensureUnusedCapacity(cg.gpa, 1);874 try cg.local_pool.locals.ensureUnusedCapacity(cg.gpa, 1);
876 assert(cg.mir_locals.items.len == cg.local_pool.locals.items.len);875 assert(cg.mir_locals.items.len == cg.local_pool.locals.items.len);
...@@ -905,7 +904,7 @@ pub fn generate(...@@ -905,7 +904,7 @@ pub fn generate(
905904
906 var code_gen: CodeGen = .{905 var code_gen: CodeGen = .{
907 .gpa = gpa,906 .gpa = gpa,
908 .pt = pt,907 .zcu = zcu,
909 .air = air.*,908 .air = air.*,
910 .liveness = liveness.*.?,909 .liveness = liveness.*.?,
911 .owner_nav = cg.owner_nav,910 .owner_nav = cg.owner_nav,
...@@ -940,7 +939,7 @@ pub fn generate(...@@ -940,7 +939,7 @@ pub fn generate(
940}939}
941940
942fn generateInner(cg: *CodeGen, any_returns: bool) InnerError!Mir {941fn generateInner(cg: *CodeGen, any_returns: bool) InnerError!Mir {
943 const zcu = cg.pt.zcu;942 const zcu = cg.zcu;
944 cg.wasm_param_count = @intCast(cg.args.len + @intFromBool(cg.return_value != .none) + @intFromBool(cg.varargs != .none));943 cg.wasm_param_count = @intCast(cg.args.len + @intFromBool(cg.return_value != .none) + @intFromBool(cg.varargs != .none));
945 cg.initial_stack_value = try cg.ensureAllocLocal(Type.usize);944 cg.initial_stack_value = try cg.ensureAllocLocal(Type.usize);
946 cg.bottom_stack_value = try cg.ensureAllocLocal(Type.usize);945 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...@@ -1099,7 +1098,7 @@ fn lowerArg(cg: *CodeGen, cc: std.lang.CallingConvention, ty: Type, value: WValu
1099 return cg.emitWValue(value);1098 return cg.emitWValue(value);
1100 }1099 }
11011100
1102 const zcu = cg.pt.zcu;1101 const zcu = cg.zcu;
11031102
1104 switch (abi.classifyType(ty, zcu, cg.target)) {1103 switch (abi.classifyType(ty, zcu, cg.target)) {
1105 .direct => |scalar_ty| {1104 .direct => |scalar_ty| {
...@@ -1148,8 +1147,7 @@ fn restoreStackPointer(cg: *CodeGen) !void {...@@ -1148,8 +1147,7 @@ fn restoreStackPointer(cg: *CodeGen) !void {
1148///1147///
1149/// Asserts Type has codegenbits1148/// Asserts Type has codegenbits
1150fn allocStack(cg: *CodeGen, ty: Type) !WValue {1149fn allocStack(cg: *CodeGen, ty: Type) !WValue {
1151 const pt = cg.pt;1150 const zcu = cg.zcu;
1152 const zcu = pt.zcu;
1153 assert(ty.hasRuntimeBits(zcu));1151 assert(ty.hasRuntimeBits(zcu));
11541152
1155 const abi_size = std.math.cast(u32, ty.abiSize(zcu)) orelse {1153 const abi_size = std.math.cast(u32, ty.abiSize(zcu)) orelse {
...@@ -1187,8 +1185,7 @@ fn allocStackBytes(cg: *CodeGen, size: u32, alignment: Alignment) !WValue {...@@ -1187,8 +1185,7 @@ fn allocStackBytes(cg: *CodeGen, size: u32, alignment: Alignment) !WValue {
1187/// This is different from allocStack where this will use the pointer's alignment1185/// This is different from allocStack where this will use the pointer's alignment
1188/// if it is set, to ensure the stack alignment will be set correctly.1186/// if it is set, to ensure the stack alignment will be set correctly.
1189fn allocStackPtr(cg: *CodeGen, inst: Air.Inst.Index) !WValue {1187fn allocStackPtr(cg: *CodeGen, inst: Air.Inst.Index) !WValue {
1190 const pt = cg.pt;1188 const zcu = cg.zcu;
1191 const zcu = pt.zcu;
1192 const ptr_ty = cg.typeOfIndex(inst);1189 const ptr_ty = cg.typeOfIndex(inst);
1193 const pointee_ty = ptr_ty.childType(zcu);1190 const pointee_ty = ptr_ty.childType(zcu);
11941191
...@@ -1338,15 +1335,25 @@ const SimdStoreStrategy = enum {...@@ -1338,15 +1335,25 @@ const SimdStoreStrategy = enum {
1338/// it using a instruction, rather than an unrolled version.1335/// it using a instruction, rather than an unrolled version.
1339pub fn determineSimdStoreStrategy(ty: Type, zcu: *const Zcu, target: *const std.Target) SimdStoreStrategy {1336pub fn determineSimdStoreStrategy(ty: Type, zcu: *const Zcu, target: *const std.Target) SimdStoreStrategy {
1340 assert(ty.zigTypeTag(zcu) == .vector);1337 assert(ty.zigTypeTag(zcu) == .vector);
1341 if (ty.bitSize(zcu) != 128) return .unrolled;1338 if (!target.cpu.has(.wasm, .simd128)) return .unrolled;
1342 if (target.cpu.has(.wasm, .relaxed_simd) or target.cpu.has(.wasm, .simd128)) {1339 return switch (ty.toIntern()) {
1343 return .direct;1340 .vector_16_i8_type,
1344 }1341 .vector_16_u8_type,
1345 return .unrolled;1342 .vector_8_i16_type,
1343 .vector_8_u16_type,
1344 .vector_4_i32_type,
1345 .vector_4_u32_type,
1346 .vector_2_i64_type,
1347 .vector_2_u64_type,
1348 .vector_4_f32_type,
1349 .vector_2_f64_type,
1350 => .direct,
1351 else => .unrolled,
1352 };
1346}1353}
13471354
1348fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {1355fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1349 const zcu = cg.pt.zcu;1356 const zcu = cg.zcu;
1350 const air_tags = cg.air.instructions.items(.tag);1357 const air_tags = cg.air.instructions.items(.tag);
1351 return switch (air_tags[@backingInt(inst)]) {1358 return switch (air_tags[@backingInt(inst)]) {
1352 // No soft float legalizations are enabled.1359 // No soft float legalizations are enabled.
...@@ -1482,7 +1489,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -1482,7 +1489,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1482 const rhs = try cg.resolveInst(bin_op.rhs);1489 const rhs = try cg.resolveInst(bin_op.rhs);
1483 const ty = cg.typeOfIndex(inst);1490 const ty = cg.typeOfIndex(inst);
14841491
1485 if (ty.zigTypeTag(cg.pt.zcu) == .vector) {1492 if (ty.zigTypeTag(cg.zcu) == .vector) {
1486 return cg.fail("TODO: implement AIR op: mul_add for vectors", .{});1493 return cg.fail("TODO: implement AIR op: mul_add for vectors", .{});
1487 }1494 }
14881495
...@@ -1500,7 +1507,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -1500,7 +1507,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1500 const rhs = try cg.resolveInst(bin_op.rhs);1507 const rhs = try cg.resolveInst(bin_op.rhs);
1501 const ty = cg.typeOfIndex(inst);1508 const ty = cg.typeOfIndex(inst);
15021509
1503 if (ty.zigTypeTag(cg.pt.zcu) == .vector) {1510 if (ty.zigTypeTag(cg.zcu) == .vector) {
1504 return cg.fail("TODO: implement AIR op: {s} for vectors", .{@tagName(tag)});1511 return cg.fail("TODO: implement AIR op: {s} for vectors", .{@tagName(tag)});
1505 }1512 }
15061513
...@@ -1545,7 +1552,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -1545,7 +1552,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1545 defer res_tmp.free(cg);1552 defer res_tmp.free(cg);
15461553
1547 const result = try cg.allocStack(cg.typeOfIndex(inst));1554 const result = try cg.allocStack(cg.typeOfIndex(inst));
1548 const offset: u32 = @intCast(ty.abiSize(cg.pt.zcu));1555 const offset: u32 = @intCast(ty.abiSize(cg.zcu));
15491556
1550 try cg.store(result, res_tmp, ty, .{});1557 try cg.store(result, res_tmp, ty, .{});
1551 try cg.store(result, ov_tmp, .u1, .{ .offset = offset });1558 try cg.store(result, ov_tmp, .u1, .{ .offset = offset });
...@@ -1665,7 +1672,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -1665,7 +1672,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1665 const src_ty = cg.typeOf(ty_op.operand);1672 const src_ty = cg.typeOf(ty_op.operand);
1666 const dest_ty = cg.typeOfIndex(inst);1673 const dest_ty = cg.typeOfIndex(inst);
16671674
1668 if (dest_ty.zigTypeTag(cg.pt.zcu) == .vector) {1675 if (dest_ty.zigTypeTag(cg.zcu) == .vector) {
1669 return cg.fail("TODO: implement AIR op: {s} for vectors", .{@tagName(tag)});1676 return cg.fail("TODO: implement AIR op: {s} for vectors", .{@tagName(tag)});
1670 }1677 }
16711678
...@@ -1949,7 +1956,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -1949,7 +1956,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1949}1956}
19501957
1951fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {1958fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
1952 const zcu = cg.pt.zcu;1959 const zcu = cg.zcu;
1953 const ip = &zcu.intern_pool;1960 const ip = &zcu.intern_pool;
19541961
1955 for (body) |inst| {1962 for (body) |inst| {
...@@ -1969,7 +1976,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -1969,7 +1976,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
1969}1976}
19701977
1971fn airRet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {1978fn airRet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1972 const zcu = cg.pt.zcu;1979 const zcu = cg.zcu;
1973 const un_op = cg.air.instructions.items(.data)[@backingInt(inst)].un_op;1980 const un_op = cg.air.instructions.items(.data)[@backingInt(inst)].un_op;
1974 const operand = try cg.resolveInst(un_op);1981 const operand = try cg.resolveInst(un_op);
1975 const fn_info = zcu.typeToFunc(zcu.navValue(cg.owner_nav).typeOf(zcu)).?;1982 const fn_info = zcu.typeToFunc(zcu.navValue(cg.owner_nav).typeOf(zcu)).?;
...@@ -2009,7 +2016,7 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2009,7 +2016,7 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2009}2016}
20102017
2011fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {2018fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2012 const zcu = cg.pt.zcu;2019 const zcu = cg.zcu;
2013 const child_type = cg.typeOfIndex(inst).childType(zcu);2020 const child_type = cg.typeOfIndex(inst).childType(zcu);
20142021
2015 const result = result: {2022 const result = result: {
...@@ -2029,7 +2036,7 @@ fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2029,7 +2036,7 @@ fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2029}2036}
20302037
2031fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {2038fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2032 const zcu = cg.pt.zcu;2039 const zcu = cg.zcu;
2033 const un_op = cg.air.instructions.items(.data)[@backingInt(inst)].un_op;2040 const un_op = cg.air.instructions.items(.data)[@backingInt(inst)].un_op;
2034 const operand = try cg.resolveInst(un_op);2041 const operand = try cg.resolveInst(un_op);
2035 const ret_ty = cg.typeOf(un_op).childType(zcu);2042 const ret_ty = cg.typeOf(un_op).childType(zcu);
...@@ -2066,8 +2073,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)...@@ -2066,8 +2073,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier)
2066 const args = call.args;2073 const args = call.args;
2067 const ty = cg.typeOf(call.callee);2074 const ty = cg.typeOf(call.callee);
20682075
2069 const pt = cg.pt;2076 const zcu = cg.zcu;
2070 const zcu = pt.zcu;
2071 const ip = &zcu.intern_pool;2077 const ip = &zcu.intern_pool;
2072 const fn_ty = switch (ty.zigTypeTag(zcu)) {2078 const fn_ty = switch (ty.zigTypeTag(zcu)) {
2073 .@"fn" => ty,2079 .@"fn" => ty,
...@@ -2240,7 +2246,7 @@ fn airVaCopy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2240,7 +2246,7 @@ fn airVaCopy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2240}2246}
22412247
2242fn airVaArg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {2248fn airVaArg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2243 const zcu = cg.pt.zcu;2249 const zcu = cg.zcu;
2244 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;2250 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
2245 const operand = try cg.resolveInst(ty_op.operand);2251 const operand = try cg.resolveInst(ty_op.operand);
22462252
...@@ -2312,8 +2318,7 @@ fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2312,8 +2318,7 @@ fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2312}2318}
23132319
2314fn airStore(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {2320fn airStore(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {
2315 const pt = cg.pt;2321 const zcu = cg.zcu;
2316 const zcu = pt.zcu;
2317 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;2322 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;
23182323
2319 const lhs = try cg.resolveInst(bin_op.lhs);2324 const lhs = try cg.resolveInst(bin_op.lhs);
...@@ -2356,8 +2361,7 @@ const MemArg = struct {...@@ -2356,8 +2361,7 @@ const MemArg = struct {
23562361
2357fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, memarg: MemArg) InnerError!void {2362fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, memarg: MemArg) InnerError!void {
2358 assert(!(lhs != .stack and rhs == .stack));2363 assert(!(lhs != .stack and rhs == .stack));
2359 const pt = cg.pt;2364 const zcu = cg.zcu;
2360 const zcu = pt.zcu;
2361 const abi_size = ty.abiSize(zcu);2365 const abi_size = ty.abiSize(zcu);
23622366
2363 if (!ty.hasRuntimeBits(zcu)) return;2367 if (!ty.hasRuntimeBits(zcu)) return;
...@@ -2422,8 +2426,7 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, memarg: MemArg) Inner...@@ -2422,8 +2426,7 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, memarg: MemArg) Inner
2422}2426}
24232427
2424fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {2428fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2425 const pt = cg.pt;2429 const zcu = cg.zcu;
2426 const zcu = pt.zcu;
2427 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;2430 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
2428 const operand = try cg.resolveInst(ty_op.operand);2431 const operand = try cg.resolveInst(ty_op.operand);
2429 const elem_ty = ty_op.ty;2432 const elem_ty = ty_op.ty;
...@@ -2449,7 +2452,7 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -2449,7 +2452,7 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2449/// Loads an operand from the linear memory section.2452/// Loads an operand from the linear memory section.
2450/// NOTE: Leaves the value on the stack, if isByRef == false.2453/// NOTE: Leaves the value on the stack, if isByRef == false.
2451fn load(cg: *CodeGen, operand: WValue, ty: Type, memarg: MemArg) InnerError!WValue {2454fn load(cg: *CodeGen, operand: WValue, ty: Type, memarg: MemArg) InnerError!WValue {
2452 const zcu = cg.pt.zcu;2455 const zcu = cg.zcu;
24532456
2454 const natural_alignment = ty.abiAlignment(zcu);2457 const natural_alignment = ty.abiAlignment(zcu);
2455 // wasm memory instruction alignment is <= access width2458 // wasm memory instruction alignment is <= access width
...@@ -2527,8 +2530,7 @@ fn load(cg: *CodeGen, operand: WValue, ty: Type, memarg: MemArg) InnerError!WVal...@@ -2527,8 +2530,7 @@ fn load(cg: *CodeGen, operand: WValue, ty: Type, memarg: MemArg) InnerError!WVal
2527}2530}
25282531
2529fn airArg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {2532fn airArg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2530 const pt = cg.pt;2533 const zcu = cg.zcu;
2531 const zcu = pt.zcu;
2532 const arg_index = cg.arg_index;2534 const arg_index = cg.arg_index;
2533 const arg = cg.args[arg_index];2535 const arg = cg.args[arg_index];
2534 const cc = zcu.typeToFunc(zcu.navValue(cg.owner_nav).typeOf(zcu)).?.cc;2536 const cc = zcu.typeToFunc(zcu.navValue(cg.owner_nav).typeOf(zcu)).?.cc;
...@@ -2580,7 +2582,7 @@ const IntType = struct {...@@ -2580,7 +2582,7 @@ const IntType = struct {
2580 // Adapted from x86_64 backend2582 // Adapted from x86_64 backend
2581 // Differ from Type.intInfo as it treats pointers/booleans/packed/enums/errors as integer2583 // Differ from Type.intInfo as it treats pointers/booleans/packed/enums/errors as integer
2582 fn fromType(cg: *CodeGen, ty: Type) IntType {2584 fn fromType(cg: *CodeGen, ty: Type) IntType {
2583 const zcu = cg.pt.zcu;2585 const zcu = cg.zcu;
2584 const ip = &zcu.intern_pool;2586 const ip = &zcu.intern_pool;
2585 var ty_index = ty.ip_index;2587 var ty_index = ty.ip_index;
2586 while (true) switch (ip.indexToKey(ty_index)) {2588 while (true) switch (ip.indexToKey(ty_index)) {
...@@ -2589,17 +2591,11 @@ const IntType = struct {...@@ -2589,17 +2591,11 @@ const IntType = struct {
2589 .one, .many, .c => .{ .is_signed = false, .bits = cg.target.ptrBitWidth() },2591 .one, .many, .c => .{ .is_signed = false, .bits = cg.target.ptrBitWidth() },
2590 .slice => unreachable,2592 .slice => unreachable,
2591 },2593 },
2592 .opt_type => |opt_child| return if (!Type.fromInterned(opt_child).hasRuntimeBits(zcu))2594 .opt_type => |opt_child| {
2593 .{ .is_signed = false, .bits = 1 }2595 if (!Type.fromInterned(opt_child).hasRuntimeBits(zcu))
2594 else switch (ip.indexToKey(opt_child)) {2596 return .{ .is_signed = false, .bits = 1 };
2595 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {2597 assert(Type.fromInterned(ty_index).optionalReprIsPayload(zcu));
2596 .one, .many => switch (ptr_type.flags.is_allowzero) {2598 ty_index = opt_child;
2597 false => .{ .is_signed = false, .bits = cg.target.ptrBitWidth() },
2598 true => unreachable,
2599 },
2600 .slice, .c => unreachable,
2601 },
2602 else => unreachable,
2603 },2599 },
2604 .error_union_type => |error_union_type| return if (!Type.fromInterned(error_union_type.payload_type)2600 .error_union_type => |error_union_type| return if (!Type.fromInterned(error_union_type.payload_type)
2605 .hasRuntimeBits(zcu)) .{ .is_signed = false, .bits = zcu.errorSetBits() } else unreachable,2601 .hasRuntimeBits(zcu)) .{ .is_signed = false, .bits = zcu.errorSetBits() } else unreachable,
...@@ -5037,8 +5033,7 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal...@@ -5037,8 +5033,7 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal
5037}5033}
50385034
5039fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerError!WValue {5035fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerError!WValue {
5040 const pt = cg.pt;5036 const zcu = cg.zcu;
5041 const zcu = pt.zcu;
5042 const ip = &zcu.intern_pool;5037 const ip = &zcu.intern_pool;
5043 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;5038 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
5044 const offset: u64 = prev_offset + ptr.byte_offset;5039 const offset: u64 = prev_offset + ptr.byte_offset;
...@@ -5052,7 +5047,10 @@ fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerErro...@@ -5052,7 +5047,10 @@ fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerErro
5052 .{ .uav_ref = .{ .ip_index = uav.val, .offset = @intCast(offset), .orig_ptr_ty = uav.orig_ty } }5047 .{ .uav_ref = .{ .ip_index = uav.val, .offset = @intCast(offset), .orig_ptr_ty = uav.orig_ty } }
5053 else5048 else
5054 .{ .imm32 = @intCast(Type.fromInterned(uav.orig_ty).ptrAlignment(zcu).forward(@as(u32, 0xaaaaaaaa))) },5049 .{ .imm32 = @intCast(Type.fromInterned(uav.orig_ty).ptrAlignment(zcu).forward(@as(u32, 0xaaaaaaaa))) },
5055 .int => return cg.lowerConstant(try pt.intValue(.usize, offset)),5050 .int => return switch (cg.ptr_size) {
5051 .wasm32 => .{ .imm32 = @intCast(offset) },
5052 .wasm64 => .{ .imm64 = offset },
5053 },
5056 .eu_payload => |eu_ptr| try cg.lowerPtr(5054 .eu_payload => |eu_ptr| try cg.lowerPtr(
5057 eu_ptr,5055 eu_ptr,
5058 offset + codegen.errUnionPayloadOffset(5056 offset + codegen.errUnionPayloadOffset(
...@@ -5091,8 +5089,7 @@ fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerErro...@@ -5091,8 +5089,7 @@ fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerErro
50915089
5092/// Asserts that `isByRef` returns `false` for `val.typeOf(zcu)`.5090/// Asserts that `isByRef` returns `false` for `val.typeOf(zcu)`.
5093fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue {5091fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue {
5094 const pt = cg.pt;5092 const zcu = cg.zcu;
5095 const zcu = pt.zcu;
5096 const ty = val.typeOf(zcu);5093 const ty = val.typeOf(zcu);
5097 assert(!isByRef(ty, zcu, cg.target));5094 assert(!isByRef(ty, zcu, cg.target));
5098 const ip = &zcu.intern_pool;5095 const ip = &zcu.intern_pool;
...@@ -5150,22 +5147,16 @@ fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue {...@@ -5150,22 +5147,16 @@ fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue {
5150 }5147 }
5151 },5148 },
5152 .err => |err| {5149 .err => |err| {
5153 const int = try pt.getErrorValue(err.name);5150 const int = ip.getErrorValueIfExists(err.name).?;
5154 return .{ .imm32 = int };5151 return .{ .imm32 = int };
5155 },5152 },
5156 .error_union => |error_union| {5153 .error_union => |error_union| {
5157 const err_int_ty = try pt.errorIntType();
5158 const err_val: Value = switch (error_union.val) {
5159 .err_name => |err_name| .fromInterned(try pt.intern(.{ .err = .{
5160 .ty = ty.errorUnionSet(zcu).toIntern(),
5161 .name = err_name,
5162 } })),
5163 .payload => try pt.intValue(err_int_ty, 0),
5164 };
5165 const payload_type = ty.errorUnionPayload(zcu);5154 const payload_type = ty.errorUnionPayload(zcu);
5166 if (!payload_type.hasRuntimeBits(zcu)) {5155 if (!payload_type.hasRuntimeBits(zcu)) {
5167 // We use the error type directly as the type.5156 return .{ .imm32 = switch (error_union.val) {
5168 return cg.lowerConstant(err_val);5157 .err_name => |err_name| ip.getErrorValueIfExists(err_name).?,
5158 .payload => 0,
5159 } };
5169 }5160 }
51705161
5171 return cg.fail("Wasm TODO: lowerConstant error union with non-zero-bit payload type", .{});5162 return cg.fail("Wasm TODO: lowerConstant error union with non-zero-bit payload type", .{});
...@@ -5188,12 +5179,27 @@ fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue {...@@ -5188,12 +5179,27 @@ fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue {
5188 } else {5179 } else {
5189 return .{ .imm32 = @intFromBool(!val.isNull(zcu)) };5180 return .{ .imm32 = @intFromBool(!val.isNull(zcu)) };
5190 },5181 },
5191 .aggregate => switch (ip.indexToKey(ty.ip_index)) {5182 .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) {
5192 .array_type => return cg.fail("Wasm TODO: LowerConstant for {f}", .{ty.fmt(zcu)}),5183 .array_type => unreachable,
5193 .vector_type => {5184 .vector_type => |vector_type| {
5194 assert(determineSimdStoreStrategy(ty, zcu, cg.target) == .direct);5185 assert(determineSimdStoreStrategy(ty, zcu, cg.target) == .direct);
5195 var buf: [16]u8 = undefined;5186 var buf: [16]u8 = undefined;
5196 val.writeToMemory(zcu, &buf) catch unreachable;5187 const elem_size: usize = @intCast(Type.fromInterned(vector_type.child).abiSize(zcu));
5188 for (0..vector_type.len) |i| {
5189 const dest = buf[i * elem_size ..][0..elem_size];
5190 const elem: Value = switch (aggregate.storage) {
5191 .bytes => |bytes| {
5192 dest[0] = bytes.at(i, ip);
5193 continue;
5194 },
5195 .elems => |elems| .fromInterned(elems[i]),
5196 .repeated_elem => |elem| .fromInterned(elem),
5197 };
5198 elem.writeToMemory(zcu, dest) catch |err| switch (err) {
5199 error.OutOfMemory => return error.OutOfMemory,
5200 error.ReinterpretDeclRef, error.IllDefinedMemoryLayout => unreachable,
5201 };
5202 }
5197 return cg.storeSimdImmd(buf);5203 return cg.storeSimdImmd(buf);
5198 },5204 },
5199 .struct_type => unreachable, // packed structs use `bitpack`5205 .struct_type => unreachable, // packed structs use `bitpack`
...@@ -5214,8 +5220,9 @@ fn storeSimdImmd(cg: *CodeGen, value: [16]u8) !WValue {...@@ -5214,8 +5220,9 @@ fn storeSimdImmd(cg: *CodeGen, value: [16]u8) !WValue {
5214}5220}
52155221
5216fn emitUndefined(cg: *CodeGen, ty: Type) InnerError!WValue {5222fn emitUndefined(cg: *CodeGen, ty: Type) InnerError!WValue {
5217 const zcu = cg.pt.zcu;5223 const zcu = cg.zcu;
5218 switch (ty.zigTypeTag(zcu)) {5224 switch (ty.zigTypeTag(zcu)) {
5225 .vector => return cg.storeSimdImmd(@splat(0xaa)),
5219 .bool, .error_set => return .{ .imm32 = 0xaaaaaaaa },5226 .bool, .error_set => return .{ .imm32 = 0xaaaaaaaa },
5220 .int, .@"enum" => switch (ty.intInfo(zcu).bits) {5227 .int, .@"enum" => switch (ty.intInfo(zcu).bits) {
5221 0...32 => return .{ .imm32 = 0xaaaaaaaa },5228 0...32 => return .{ .imm32 = 0xaaaaaaaa },
...@@ -5256,7 +5263,7 @@ fn airBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5256,7 +5263,7 @@ fn airBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5256}5263}
52575264
5258fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, block_ty: Type, body: []const Air.Inst.Index) InnerError!void {5265fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, block_ty: Type, body: []const Air.Inst.Index) InnerError!void {
5259 const zcu = cg.pt.zcu;5266 const zcu = cg.zcu;
52605267
5261 if (block_ty.isNoReturn(zcu)) {5268 if (block_ty.isNoReturn(zcu)) {
5262 assert(cg.liveness.getBlock(inst).deaths.len == 0);5269 assert(cg.liveness.getBlock(inst).deaths.len == 0);
...@@ -5365,7 +5372,7 @@ fn airCmp(cg: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) Inne...@@ -5365,7 +5372,7 @@ fn airCmp(cg: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) Inne
5365 const lhs = try cg.resolveInst(bin_op.lhs);5372 const lhs = try cg.resolveInst(bin_op.lhs);
5366 const rhs = try cg.resolveInst(bin_op.rhs);5373 const rhs = try cg.resolveInst(bin_op.rhs);
5367 const operand_ty = cg.typeOf(bin_op.lhs);5374 const operand_ty = cg.typeOf(bin_op.lhs);
5368 const zcu = cg.pt.zcu;5375 const zcu = cg.zcu;
53695376
5370 const type_tag = operand_ty.zigTypeTag(zcu);5377 const type_tag = operand_ty.zigTypeTag(zcu);
53715378
...@@ -5597,10 +5604,10 @@ fn airCmpLteErrorsLen(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5597,10 +5604,10 @@ fn airCmpLteErrorsLen(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5597 const operand = try cg.resolveInst(un_op);5604 const operand = try cg.resolveInst(un_op);
55985605
5599 try cg.emitWValue(operand);5606 try cg.emitWValue(operand);
5600 const pt = cg.pt;5607 const zcu = cg.zcu;
5601 const err_int_ty = try pt.errorIntType();5608 const err_int_ty: IntType = .{ .is_signed = false, .bits = zcu.errorSetBits() };
5602 try cg.addTag(.errors_len);5609 try cg.addTag(.errors_len);
5603 const result = try cg.intCmp(.fromType(cg, err_int_ty), .lt, .stack, .stack);5610 const result = try cg.intCmp(err_int_ty, .lt, .stack, .stack);
56045611
5605 return cg.finishAir(inst, result, &.{un_op});5612 return cg.finishAir(inst, result, &.{un_op});
5606}5613}
...@@ -5656,7 +5663,7 @@ fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5656,7 +5663,7 @@ fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5656}5663}
56575664
5658fn airNopCast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {5665fn airNopCast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5659 const zcu = cg.pt.zcu;5666 const zcu = cg.zcu;
5660 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;5667 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
56615668
5662 const operand_ty = cg.typeOf(ty_op.operand);5669 const operand_ty = cg.typeOf(ty_op.operand);
...@@ -5670,7 +5677,7 @@ fn airNopCast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5670,7 +5677,7 @@ fn airNopCast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5670}5677}
56715678
5672fn airIntFromPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {5679fn airIntFromPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5673 const zcu = cg.pt.zcu;5680 const zcu = cg.zcu;
5674 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;5681 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
56755682
5676 const operand_ty = cg.typeOf(ty_op.operand);5683 const operand_ty = cg.typeOf(ty_op.operand);
...@@ -5689,7 +5696,7 @@ fn airIntFromPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5689,7 +5696,7 @@ fn airIntFromPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5689}5696}
56905697
5691fn airUnionFromEnum(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {5698fn airUnionFromEnum(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5692 const zcu = cg.pt.zcu;5699 const zcu = cg.zcu;
5693 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;5700 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
56945701
5695 const union_ty = cg.typeOfIndex(inst);5702 const union_ty = cg.typeOfIndex(inst);
...@@ -5721,7 +5728,7 @@ const BitcastClass = union(enum) {...@@ -5721,7 +5728,7 @@ const BitcastClass = union(enum) {
5721};5728};
57225729
5723fn bitcastClass(cg: *CodeGen, ty: Type) BitcastClass {5730fn bitcastClass(cg: *CodeGen, ty: Type) BitcastClass {
5724 const zcu = cg.pt.zcu;5731 const zcu = cg.zcu;
5725 return switch (ty.zigTypeTag(zcu)) {5732 return switch (ty.zigTypeTag(zcu)) {
5726 .bool,5733 .bool,
5727 .int,5734 .int,
...@@ -5739,7 +5746,7 @@ fn bitcastClass(cg: *CodeGen, ty: Type) BitcastClass {...@@ -5739,7 +5746,7 @@ fn bitcastClass(cg: *CodeGen, ty: Type) BitcastClass {
5739fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerError!WValue {5746fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerError!WValue {
5740 if (dest_ty.eql(src_ty)) return operand;5747 if (dest_ty.eql(src_ty)) return operand;
57415748
5742 const zcu = cg.pt.zcu;5749 const zcu = cg.zcu;
5743 const src_class = cg.bitcastClass(src_ty);5750 const src_class = cg.bitcastClass(src_ty);
5744 const dest_class = cg.bitcastClass(dest_ty);5751 const dest_class = cg.bitcastClass(dest_ty);
5745 const src_by_ref = isByRef(src_ty, zcu, cg.target);5752 const src_by_ref = isByRef(src_ty, zcu, cg.target);
...@@ -5785,7 +5792,7 @@ fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerErro...@@ -5785,7 +5792,7 @@ fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerErro
5785 .f80, .f128 => unreachable,5792 .f80, .f128 => unreachable,
5786 },5793 },
5787 .int => {},5794 .int => {},
5788 .aggregate => unreachable,5795 .aggregate => return operand, // both v128
5789 }5796 }
57905797
5791 switch (dest_class) {5798 switch (dest_class) {
...@@ -5815,7 +5822,7 @@ fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerErro...@@ -5815,7 +5822,7 @@ fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerErro
5815}5822}
58165823
5817fn airStructFieldPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {5824fn airStructFieldPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5818 const zcu = cg.pt.zcu;5825 const zcu = cg.zcu;
5819 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;5826 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
5820 const extra = cg.air.extraData(Air.StructField, ty_pl.payload);5827 const extra = cg.air.extraData(Air.StructField, ty_pl.payload);
58215828
...@@ -5827,7 +5834,7 @@ fn airStructFieldPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5827,7 +5834,7 @@ fn airStructFieldPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5827}5834}
58285835
5829fn airStructFieldPtrIndex(cg: *CodeGen, inst: Air.Inst.Index, index: u32) InnerError!void {5836fn airStructFieldPtrIndex(cg: *CodeGen, inst: Air.Inst.Index, index: u32) InnerError!void {
5830 const zcu = cg.pt.zcu;5837 const zcu = cg.zcu;
5831 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;5838 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
5832 const struct_ptr = try cg.resolveInst(ty_op.operand);5839 const struct_ptr = try cg.resolveInst(ty_op.operand);
5833 const struct_ptr_ty = cg.typeOf(ty_op.operand);5840 const struct_ptr_ty = cg.typeOf(ty_op.operand);
...@@ -5845,8 +5852,7 @@ fn structFieldPtr(...@@ -5845,8 +5852,7 @@ fn structFieldPtr(
5845 struct_ty: Type,5852 struct_ty: Type,
5846 index: u32,5853 index: u32,
5847) InnerError!WValue {5854) InnerError!WValue {
5848 const pt = cg.pt;5855 const zcu = cg.zcu;
5849 const zcu = pt.zcu;
5850 const result_ty = cg.typeOfIndex(inst);5856 const result_ty = cg.typeOfIndex(inst);
5851 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(zcu);5857 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(zcu);
58525858
...@@ -5868,8 +5874,7 @@ fn structFieldPtr(...@@ -5868,8 +5874,7 @@ fn structFieldPtr(
5868}5874}
58695875
5870fn airAggFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {5876fn airAggFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5871 const pt = cg.pt;5877 const zcu = cg.zcu;
5872 const zcu = pt.zcu;
5873 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;5878 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
5874 const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data;5879 const struct_field = cg.air.extraData(Air.StructField, ty_pl.payload).data;
58755880
...@@ -5897,8 +5902,7 @@ fn airAggFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -5897,8 +5902,7 @@ fn airAggFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
58975902
5898// Both `.switch_br` and `.loop_switch_br` are noreturn.5903// Both `.switch_br` and `.loop_switch_br` are noreturn.
5899fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) InnerError!void {5904fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) InnerError!void {
5900 const pt = cg.pt;5905 const zcu = cg.zcu;
5901 const zcu = pt.zcu;
59025906
5903 const switch_br = cg.air.unwrapSwitch(inst);5907 const switch_br = cg.air.unwrapSwitch(inst);
5904 const target_ty = cg.typeOf(switch_br.operand);5908 const target_ty = cg.typeOf(switch_br.operand);
...@@ -6013,6 +6017,13 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner...@@ -6013,6 +6017,13 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner
6013 if (use_br_table) {6017 if (use_br_table) {
6014 const width = width_maybe.?;6018 const width = width_maybe.?;
60156019
6020 if (int_ty.bits > 32) {
6021 _ = try cg.intCmp(int_ty, .lt, target, try cg.resolveValue(min.?));
6022 try cg.addLabel(.br_if, branch_count - 1);
6023 _ = try cg.intCmp(int_ty, .gt, target, try cg.resolveValue(max.?));
6024 try cg.addLabel(.br_if, branch_count - 1);
6025 }
6026
6016 const br_value_original = try cg.intSub(int_ty, target, try cg.resolveValue(min.?));6027 const br_value_original = try cg.intSub(int_ty, target, try cg.resolveValue(min.?));
6017 _ = try cg.intCast(.u32, int_ty, br_value_original);6028 _ = try cg.intCast(.u32, int_ty, br_value_original);
60186029
...@@ -6119,7 +6130,7 @@ fn airSwitchDispatch(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6119,7 +6130,7 @@ fn airSwitchDispatch(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6119}6130}
61206131
6121fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kind: enum { value, ptr }) InnerError!void {6132fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kind: enum { value, ptr }) InnerError!void {
6122 const zcu = cg.pt.zcu;6133 const zcu = cg.zcu;
6123 const un_op = cg.air.instructions.items(.data)[@backingInt(inst)].un_op;6134 const un_op = cg.air.instructions.items(.data)[@backingInt(inst)].un_op;
6124 const operand = try cg.resolveInst(un_op);6135 const operand = try cg.resolveInst(un_op);
6125 const err_union_ty = switch (op_kind) {6136 const err_union_ty = switch (op_kind) {
...@@ -6158,7 +6169,7 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kind...@@ -6158,7 +6169,7 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kind
6158/// E!T -> T op_is_ptr == false6169/// E!T -> T op_is_ptr == false
6159/// *(E!T) -> *T op_is_prt == true6170/// *(E!T) -> *T op_is_prt == true
6160fn airUnwrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {6171fn airUnwrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {
6161 const zcu = cg.pt.zcu;6172 const zcu = cg.zcu;
6162 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;6173 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
61636174
6164 const operand = try cg.resolveInst(ty_op.operand);6175 const operand = try cg.resolveInst(ty_op.operand);
...@@ -6190,7 +6201,7 @@ fn airUnwrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool)...@@ -6190,7 +6201,7 @@ fn airUnwrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool)
6190/// *(E!T) -> E op_is_ptr == true6201/// *(E!T) -> E op_is_ptr == true
6191/// NOTE: op_is_ptr will not change return type6202/// NOTE: op_is_ptr will not change return type
6192fn airUnwrapErrUnionError(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {6203fn airUnwrapErrUnionError(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {
6193 const zcu = cg.pt.zcu;6204 const zcu = cg.zcu;
6194 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;6205 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
61956206
6196 const operand = try cg.resolveInst(ty_op.operand);6207 const operand = try cg.resolveInst(ty_op.operand);
...@@ -6215,7 +6226,7 @@ fn airUnwrapErrUnionError(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) I...@@ -6215,7 +6226,7 @@ fn airUnwrapErrUnionError(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) I
6215}6226}
62166227
6217fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {6228fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6218 const zcu = cg.pt.zcu;6229 const zcu = cg.zcu;
6219 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;6230 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
62206231
6221 const operand = try cg.resolveInst(ty_op.operand);6232 const operand = try cg.resolveInst(ty_op.operand);
...@@ -6244,7 +6255,7 @@ fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6244,7 +6255,7 @@ fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6244}6255}
62456256
6246fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {6257fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6247 const zcu = cg.pt.zcu;6258 const zcu = cg.zcu;
6248 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;6259 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
62496260
6250 const operand = try cg.resolveInst(ty_op.operand);6261 const operand = try cg.resolveInst(ty_op.operand);
...@@ -6284,8 +6295,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kin...@@ -6284,8 +6295,7 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kin
6284/// For a given type and operand, checks if it's considered `null`.6295/// For a given type and operand, checks if it's considered `null`.
6285/// NOTE: Leaves the result on the stack6296/// NOTE: Leaves the result on the stack
6286fn isNull(cg: *CodeGen, operand: WValue, op_ty: Type, opcode: std.wasm.Opcode, op_kind: OpKind) InnerError!WValue {6297fn isNull(cg: *CodeGen, operand: WValue, op_ty: Type, opcode: std.wasm.Opcode, op_kind: OpKind) InnerError!WValue {
6287 const pt = cg.pt;6298 const zcu = cg.zcu;
6288 const zcu = pt.zcu;
6289 const optional_ty = switch (op_kind) {6299 const optional_ty = switch (op_kind) {
6290 .value => op_ty,6300 .value => op_ty,
6291 .ptr => op_ty.childType(zcu),6301 .ptr => op_ty.childType(zcu),
...@@ -6330,7 +6340,7 @@ fn isNull(cg: *CodeGen, operand: WValue, op_ty: Type, opcode: std.wasm.Opcode, o...@@ -6330,7 +6340,7 @@ fn isNull(cg: *CodeGen, operand: WValue, op_ty: Type, opcode: std.wasm.Opcode, o
6330}6340}
63316341
6332fn airOptionalPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {6342fn airOptionalPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6333 const zcu = cg.pt.zcu;6343 const zcu = cg.zcu;
6334 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;6344 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
6335 const opt_ty = cg.typeOf(ty_op.operand);6345 const opt_ty = cg.typeOf(ty_op.operand);
6336 const payload_ty = cg.typeOfIndex(inst);6346 const payload_ty = cg.typeOfIndex(inst);
...@@ -6352,7 +6362,7 @@ fn airOptionalPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6352,7 +6362,7 @@ fn airOptionalPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6352}6362}
63536363
6354fn airOptionalPayloadPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {6364fn airOptionalPayloadPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6355 const zcu = cg.pt.zcu;6365 const zcu = cg.zcu;
6356 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;6366 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
6357 const operand = try cg.resolveInst(ty_op.operand);6367 const operand = try cg.resolveInst(ty_op.operand);
6358 const opt_ty = cg.typeOf(ty_op.operand).childType(zcu);6368 const opt_ty = cg.typeOf(ty_op.operand).childType(zcu);
...@@ -6369,8 +6379,7 @@ fn airOptionalPayloadPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6369,8 +6379,7 @@ fn airOptionalPayloadPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6369}6379}
63706380
6371fn airOptionalPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {6381fn airOptionalPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6372 const pt = cg.pt;6382 const zcu = cg.zcu;
6373 const zcu = pt.zcu;
6374 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;6383 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
6375 const operand = try cg.resolveInst(ty_op.operand);6384 const operand = try cg.resolveInst(ty_op.operand);
6376 const opt_ty = cg.typeOf(ty_op.operand).childType(zcu);6385 const opt_ty = cg.typeOf(ty_op.operand).childType(zcu);
...@@ -6394,8 +6403,7 @@ fn airOptionalPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void...@@ -6394,8 +6403,7 @@ fn airOptionalPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void
6394fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {6403fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6395 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;6404 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
6396 const payload_ty = cg.typeOf(ty_op.operand);6405 const payload_ty = cg.typeOf(ty_op.operand);
6397 const pt = cg.pt;6406 const zcu = cg.zcu;
6398 const zcu = pt.zcu;
63996407
6400 const result = result: {6408 const result = result: {
6401 if (!payload_ty.hasRuntimeBits(zcu)) {6409 if (!payload_ty.hasRuntimeBits(zcu)) {
...@@ -6451,7 +6459,7 @@ fn airSliceLen(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6451,7 +6459,7 @@ fn airSliceLen(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6451}6459}
64526460
6453fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {6461fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6454 const zcu = cg.pt.zcu;6462 const zcu = cg.zcu;
6455 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;6463 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;
64566464
6457 const slice_ty = cg.typeOf(bin_op.lhs);6465 const slice_ty = cg.typeOf(bin_op.lhs);
...@@ -6472,7 +6480,7 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6472,7 +6480,7 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6472}6480}
64736481
6474fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {6482fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6475 const zcu = cg.pt.zcu;6483 const zcu = cg.zcu;
6476 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;6484 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
6477 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;6485 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
64786486
...@@ -6507,7 +6515,7 @@ fn sliceLen(cg: *CodeGen, operand: WValue) InnerError!WValue {...@@ -6507,7 +6515,7 @@ fn sliceLen(cg: *CodeGen, operand: WValue) InnerError!WValue {
6507}6515}
65086516
6509fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {6517fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6510 const zcu = cg.pt.zcu;6518 const zcu = cg.zcu;
6511 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;6519 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
65126520
6513 const operand = try cg.resolveInst(ty_op.operand);6521 const operand = try cg.resolveInst(ty_op.operand);
...@@ -6527,7 +6535,7 @@ fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6527,7 +6535,7 @@ fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6527}6535}
65286536
6529fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {6537fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6530 const zcu = cg.pt.zcu;6538 const zcu = cg.zcu;
6531 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;6539 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;
65326540
6533 const ptr_ty = cg.typeOf(bin_op.lhs);6541 const ptr_ty = cg.typeOf(bin_op.lhs);
...@@ -6552,7 +6560,7 @@ fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6552,7 +6560,7 @@ fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6552}6560}
65536561
6554fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {6562fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6555 const zcu = cg.pt.zcu;6563 const zcu = cg.zcu;
6556 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;6564 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
6557 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;6565 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
65586566
...@@ -6577,7 +6585,7 @@ fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6577,7 +6585,7 @@ fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6577}6585}
65786586
6579fn airPtrBinOp(cg: *CodeGen, inst: Air.Inst.Index, op: PointerOffsetOp) InnerError!void {6587fn airPtrBinOp(cg: *CodeGen, inst: Air.Inst.Index, op: PointerOffsetOp) InnerError!void {
6580 const zcu = cg.pt.zcu;6588 const zcu = cg.zcu;
6581 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;6589 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
6582 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;6590 const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data;
65836591
...@@ -6596,7 +6604,7 @@ fn airPtrBinOp(cg: *CodeGen, inst: Air.Inst.Index, op: PointerOffsetOp) InnerErr...@@ -6596,7 +6604,7 @@ fn airPtrBinOp(cg: *CodeGen, inst: Air.Inst.Index, op: PointerOffsetOp) InnerErr
6596}6604}
65976605
6598fn airMemset(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {6606fn airMemset(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {
6599 const zcu = cg.pt.zcu;6607 const zcu = cg.zcu;
6600 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;6608 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;
66016609
6602 const ptr = try cg.resolveInst(bin_op.lhs);6610 const ptr = try cg.resolveInst(bin_op.lhs);
...@@ -6630,7 +6638,7 @@ fn airMemset(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {...@@ -6630,7 +6638,7 @@ fn airMemset(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {
6630/// this to wasm's memset instruction. When the feature is not present,6638/// this to wasm's memset instruction. When the feature is not present,
6631/// we implement it manually.6639/// we implement it manually.
6632fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) InnerError!void {6640fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) InnerError!void {
6633 const zcu = cg.pt.zcu;6641 const zcu = cg.zcu;
6634 const abi_size = @as(u32, @intCast(elem_ty.abiSize(zcu)));6642 const abi_size = @as(u32, @intCast(elem_ty.abiSize(zcu)));
6635 const len_known_neq_0 = switch (len) {6643 const len_known_neq_0 = switch (len) {
6636 .imm32 => |imm| if (imm != 0) true else return,6644 .imm32 => |imm| if (imm != 0) true else return,
...@@ -6750,7 +6758,7 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue)...@@ -6750,7 +6758,7 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue)
6750}6758}
67516759
6752fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {6760fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6753 const zcu = cg.pt.zcu;6761 const zcu = cg.zcu;
6754 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;6762 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;
67556763
6756 const array_ty = cg.typeOf(bin_op.lhs);6764 const array_ty = cg.typeOf(bin_op.lhs);
...@@ -6804,7 +6812,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6804,7 +6812,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6804}6812}
68056813
6806fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {6814fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6807 const zcu = cg.pt.zcu;6815 const zcu = cg.zcu;
6808 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;6816 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
6809 const operand = try cg.resolveInst(ty_op.operand);6817 const operand = try cg.resolveInst(ty_op.operand);
6810 const ty = cg.typeOfIndex(inst);6818 const ty = cg.typeOfIndex(inst);
...@@ -6875,8 +6883,7 @@ fn airSelect(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6875,8 +6883,7 @@ fn airSelect(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6875}6883}
68766884
6877fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {6885fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6878 const pt = cg.pt;6886 const zcu = cg.zcu;
6879 const zcu = pt.zcu;
68806887
6881 const unwrapped = cg.air.unwrapShuffleOne(zcu, inst);6888 const unwrapped = cg.air.unwrapShuffleOne(zcu, inst);
6882 const result_ty = unwrapped.result_ty;6889 const result_ty = unwrapped.result_ty;
...@@ -6907,8 +6914,7 @@ fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6907,8 +6914,7 @@ fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6907}6914}
69086915
6909fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {6916fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6910 const pt = cg.pt;6917 const zcu = cg.zcu;
6911 const zcu = pt.zcu;
69126918
6913 const unwrapped = cg.air.unwrapShuffleTwo(zcu, inst);6919 const unwrapped = cg.air.unwrapShuffleTwo(zcu, inst);
6914 const result_ty = unwrapped.result_ty;6920 const result_ty = unwrapped.result_ty;
...@@ -6984,8 +6990,7 @@ fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6984,8 +6990,7 @@ fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6984}6990}
69856991
6986fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {6992fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6987 const pt = cg.pt;6993 const zcu = cg.zcu;
6988 const zcu = pt.zcu;
6989 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;6994 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
6990 const result_ty = cg.typeOfIndex(inst);6995 const result_ty = cg.typeOfIndex(inst);
6991 const len = @as(usize, @intCast(result_ty.arrayLen(zcu)));6996 const len = @as(usize, @intCast(result_ty.arrayLen(zcu)));
...@@ -6994,31 +6999,59 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -6994,31 +6999,59 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6994 const result: WValue = result_value: {6999 const result: WValue = result_value: {
6995 switch (result_ty.zigTypeTag(zcu)) {7000 switch (result_ty.zigTypeTag(zcu)) {
6996 .array, .vector => {7001 .array, .vector => {
6997 const result = try cg.allocStack(result_ty);
6998 const elem_ty = result_ty.childType(zcu);7002 const elem_ty = result_ty.childType(zcu);
6999 const elem_size = elem_ty.abiSize(zcu);7003 if (isByRef(result_ty, zcu, cg.target)) {
7000 const sentinel = result_ty.sentinel(zcu);7004 const result = try cg.allocStack(result_ty);
70017005 const elem_size = elem_ty.abiSize(zcu);
7002 var offset: u64 = 0;7006 const sentinel = result_ty.sentinel(zcu);
7003 for (elements) |elem| {7007
7004 const elem_val = try cg.resolveInst(elem);7008 var offset: u64 = 0;
7005 try cg.store(result, elem_val, elem_ty, .{ .offset = offset });7009 for (elements) |elem| {
7006 offset += elem_size;7010 const elem_val = try cg.resolveInst(elem);
7007 }7011 try cg.store(result, elem_val, elem_ty, .{ .offset = offset });
7008 if (sentinel) |s| {7012 offset += elem_size;
7009 const val = try cg.resolveValue(s);7013 }
7010 try cg.store(result, val, elem_ty, .{ .offset = offset });7014 if (sentinel) |s| {
7015 const val = try cg.resolveValue(s);
7016 try cg.store(result, val, elem_ty, .{ .offset = offset });
7017 }
7018 break :result_value result;
7019 } else {
7020 assert(result_ty.zigTypeTag(zcu) == .vector);
7021 const splat: std.wasm.SimdOpcode, const replace_lane: std.wasm.SimdOpcode = switch (elem_ty.toIntern()) {
7022 .u8_type, .i8_type => .{ .i8x16_splat, .i8x16_replace_lane },
7023 .u16_type, .i16_type => .{ .i16x8_splat, .i16x8_replace_lane },
7024 .u32_type, .i32_type => .{ .i32x4_splat, .i32x4_replace_lane },
7025 .u64_type, .i64_type => .{ .i64x2_splat, .i64x2_replace_lane },
7026 .f32_type => .{ .f32x4_splat, .f32x4_replace_lane },
7027 .f64_type => .{ .f64x2_splat, .f64x2_replace_lane },
7028 else => unreachable,
7029 };
7030
7031 // TODO: find best element to splat, if it is constant dont use splat at all
7032 try cg.emitWValue(try cg.resolveInst(elements[0]));
7033 const splat_extra: u32 = @intCast(cg.mir_extra.items.len);
7034 try cg.mir_extra.append(cg.gpa, @backingInt(splat));
7035 try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = splat_extra } });
7036 for (elements[1..], 1..) |elem, lane| {
7037 if (elem == elements[0]) continue;
7038 try cg.emitWValue(try cg.resolveInst(elem));
7039 const extra_index: u32 = @intCast(cg.mir_extra.items.len);
7040 try cg.mir_extra.appendSlice(cg.gpa, &.{ @backingInt(replace_lane), @intCast(lane) });
7041 try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } });
7042 }
7043 break :result_value .stack;
7011 }7044 }
7012 break :result_value result;
7013 },7045 },
7014 .@"struct" => switch (result_ty.containerLayout(zcu)) {7046 .@"struct" => switch (result_ty.containerLayout(zcu)) {
7015 .@"packed" => unreachable, // legalize .expand_packed_aggregate_init7047 .@"packed" => unreachable, // legalize .expand_packed_aggregate_init
7016 else => {7048 else => {
7017 const result = try cg.allocStack(result_ty);7049 const result = try cg.allocStack(result_ty);
7018 for (elements, 0..) |elem, elem_index| {7050 for (elements, 0..) |elem, elem_index| {
7019 if (try result_ty.structFieldValueComptime(pt, elem_index) != null) continue;7051 if (result_ty.structFieldIsComptime(elem_index, zcu)) continue;
70207052
7021 const elem_ty = result_ty.fieldType(elem_index, zcu);7053 const elem_ty = result_ty.fieldType(elem_index, zcu);
7054 if (!elem_ty.hasRuntimeBits(zcu)) continue;
7022 const field_offset = result_ty.structFieldOffset(elem_index, zcu);7055 const field_offset = result_ty.structFieldOffset(elem_index, zcu);
70237056
7024 const value = try cg.resolveInst(elem);7057 const value = try cg.resolveInst(elem);
...@@ -7038,8 +7071,7 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7038,8 +7071,7 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7038}7071}
70397072
7040fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {7073fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7041 const pt = cg.pt;7074 const zcu = cg.zcu;
7042 const zcu = pt.zcu;
7043 const ip = &zcu.intern_pool;7075 const ip = &zcu.intern_pool;
7044 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;7076 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
7045 const extra = cg.air.extraData(Air.UnionInit, ty_pl.payload).data;7077 const extra = cg.air.extraData(Air.UnionInit, ty_pl.payload).data;
...@@ -7051,11 +7083,27 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7051,11 +7083,27 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7051 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[extra.field_index]);7083 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[extra.field_index]);
7052 const field_name = ip.loadEnumType(union_obj.enum_tag_type).field_names.get(ip)[extra.field_index];7084 const field_name = ip.loadEnumType(union_obj.enum_tag_type).field_names.get(ip)[extra.field_index];
70537085
7054 const tag_int = blk: {7086 const tag_int: WValue = blk: {
7055 const tag_ty = union_ty.unionTagTypeHypothetical(zcu);7087 const tag_ty = union_ty.unionTagTypeHypothetical(zcu);
7056 const enum_field_index = tag_ty.enumFieldIndex(field_name, zcu).?;7088 const enum_field_index = tag_ty.enumFieldIndex(field_name, zcu).?;
7057 const tag_val = try pt.enumValueFieldIndex(tag_ty, enum_field_index);7089 const enum_type = ip.loadEnumType(tag_ty.toIntern());
7058 break :blk try cg.lowerConstant(tag_val);7090 const int_ty = Type.fromInterned(enum_type.int_tag_type);
7091 const int_bits = int_ty.intInfo(zcu).bits;
7092 if (int_bits > 64) {
7093 return cg.fail("TODO: union tags > 64 bits", .{});
7094 }
7095
7096 if (enum_type.field_values.len == 0) {
7097 // Auto-numbered fields.
7098 break :blk switch (int_bits) {
7099 0...32 => .{ .imm32 = enum_field_index },
7100 33...64 => .{ .imm64 = enum_field_index },
7101 else => unreachable,
7102 };
7103 }
7104
7105 const int_value = enum_type.field_values.get(ip)[enum_field_index];
7106 break :blk try cg.lowerConstant(.fromInterned(int_value));
7059 };7107 };
7060 if (layout.payload_size == 0) {7108 if (layout.payload_size == 0) {
7061 if (layout.tag_size == 0) {7109 if (layout.tag_size == 0) {
...@@ -7116,8 +7164,7 @@ fn airWasmMemoryGrow(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -7116,8 +7164,7 @@ fn airWasmMemoryGrow(cg: *CodeGen, inst: Air.Inst.Index) !void {
7116}7164}
71177165
7118fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {7166fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7119 const pt = cg.pt;7167 const zcu = cg.zcu;
7120 const zcu = pt.zcu;
7121 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;7168 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;
7122 const un_ty = cg.typeOf(bin_op.lhs).childType(zcu);7169 const un_ty = cg.typeOf(bin_op.lhs).childType(zcu);
7123 const tag_ty = cg.typeOf(bin_op.rhs);7170 const tag_ty = cg.typeOf(bin_op.rhs);
...@@ -7141,7 +7188,7 @@ fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7141,7 +7188,7 @@ fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7141}7188}
71427189
7143fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {7190fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7144 const zcu = cg.pt.zcu;7191 const zcu = cg.zcu;
7145 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;7192 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
71467193
7147 const un_ty = cg.typeOf(ty_op.operand);7194 const un_ty = cg.typeOf(ty_op.operand);
...@@ -7161,7 +7208,7 @@ fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7161,7 +7208,7 @@ fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7161}7208}
71627209
7163fn airErrUnionPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {7210fn airErrUnionPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7164 const zcu = cg.pt.zcu;7211 const zcu = cg.zcu;
7165 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;7212 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
71667213
7167 const err_set_ty = cg.typeOf(ty_op.operand).childType(zcu);7214 const err_set_ty = cg.typeOf(ty_op.operand).childType(zcu);
...@@ -7185,8 +7232,7 @@ fn airErrUnionPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void...@@ -7185,8 +7232,7 @@ fn airErrUnionPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void
7185}7232}
71867233
7187fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {7234fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7188 const pt = cg.pt;7235 const zcu = cg.zcu;
7189 const zcu = pt.zcu;
7190 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;7236 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
7191 const extra = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;7237 const extra = cg.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
71927238
...@@ -7225,7 +7271,7 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7225,7 +7271,7 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7225}7271}
72267272
7227fn sliceOrArrayPtr(cg: *CodeGen, ptr: WValue, ptr_ty: Type) InnerError!WValue {7273fn sliceOrArrayPtr(cg: *CodeGen, ptr: WValue, ptr_ty: Type) InnerError!WValue {
7228 const zcu = cg.pt.zcu;7274 const zcu = cg.zcu;
7229 if (ptr_ty.isSlice(zcu)) {7275 if (ptr_ty.isSlice(zcu)) {
7230 return cg.slicePtr(ptr);7276 return cg.slicePtr(ptr);
7231 } else {7277 } else {
...@@ -7234,7 +7280,7 @@ fn sliceOrArrayPtr(cg: *CodeGen, ptr: WValue, ptr_ty: Type) InnerError!WValue {...@@ -7234,7 +7280,7 @@ fn sliceOrArrayPtr(cg: *CodeGen, ptr: WValue, ptr_ty: Type) InnerError!WValue {
7234}7280}
72357281
7236fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {7282fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7237 const zcu = cg.pt.zcu;7283 const zcu = cg.zcu;
7238 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;7284 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;
7239 const dst = try cg.resolveInst(bin_op.lhs);7285 const dst = try cg.resolveInst(bin_op.lhs);
7240 const dst_ty = cg.typeOf(bin_op.lhs);7286 const dst_ty = cg.typeOf(bin_op.lhs);
...@@ -7268,7 +7314,7 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7268,7 +7314,7 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7268}7314}
72697315
7270fn airMemmove(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {7316fn airMemmove(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7271 const zcu = cg.pt.zcu;7317 const zcu = cg.zcu;
7272 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;7318 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;
7273 const dst = try cg.resolveInst(bin_op.lhs);7319 const dst = try cg.resolveInst(bin_op.lhs);
7274 const dst_ty = cg.typeOf(bin_op.lhs);7320 const dst_ty = cg.typeOf(bin_op.lhs);
...@@ -7319,9 +7365,9 @@ fn airErrorName(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7319,9 +7365,9 @@ fn airErrorName(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7319 //7365 //
7320 // As the names are global and the slice elements are constant, we do not have7366 // As the names are global and the slice elements are constant, we do not have
7321 // to make a copy of the ptr+value but can point towards them directly.7367 // to make a copy of the ptr+value but can point towards them directly.
7322 const pt = cg.pt;7368 const zcu = cg.zcu;
7323 const name_ty = Type.slice_const_u8_sentinel_0;7369 const name_ty = Type.slice_const_u8_sentinel_0;
7324 const abi_size = name_ty.abiSize(pt.zcu);7370 const abi_size = name_ty.abiSize(zcu);
73257371
7326 // Lowers to a i32.const or i64.const with the error table memory address.7372 // Lowers to a i32.const or i64.const with the error table memory address.
7327 cg.error_name_table_ref_count += 1;7373 cg.error_name_table_ref_count += 1;
...@@ -7382,7 +7428,7 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7382,7 +7428,7 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7382}7428}
73837429
7384fn airTryPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {7430fn airTryPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7385 const zcu = cg.pt.zcu;7431 const zcu = cg.zcu;
7386 const unwrapped_try = cg.air.unwrapTryPtr(inst);7432 const unwrapped_try = cg.air.unwrapTryPtr(inst);
7387 const err_union_ptr = try cg.resolveInst(unwrapped_try.error_union_ptr);7433 const err_union_ptr = try cg.resolveInst(unwrapped_try.error_union_ptr);
7388 const body = unwrapped_try.else_body;7434 const body = unwrapped_try.else_body;
...@@ -7405,7 +7451,7 @@ fn lowerTry(...@@ -7405,7 +7451,7 @@ fn lowerTry(
7405 err_union_ty: Type,7451 err_union_ty: Type,
7406 operand_is_ptr: bool,7452 operand_is_ptr: bool,
7407) InnerError!WValue {7453) InnerError!WValue {
7408 const zcu = cg.pt.zcu;7454 const zcu = cg.zcu;
7409 const branch_liveness = cg.liveness.getCondBr(inst);7455 const branch_liveness = cg.liveness.getCondBr(inst);
74107456
7411 const pl_ty = err_union_ty.errorUnionPayload(zcu);7457 const pl_ty = err_union_ty.errorUnionPayload(zcu);
...@@ -7465,7 +7511,7 @@ fn callIntrinsic(...@@ -7465,7 +7511,7 @@ fn callIntrinsic(
7465 args: []const WValue,7511 args: []const WValue,
7466) InnerError!WValue {7512) InnerError!WValue {
7467 assert(param_types.len == args.len);7513 assert(param_types.len == args.len);
7468 const zcu = cg.pt.zcu;7514 const zcu = cg.zcu;
74697515
7470 // Always pass over C-ABI7516 // Always pass over C-ABI
74717517
...@@ -7523,7 +7569,7 @@ fn airIsNamedEnumValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7523,7 +7569,7 @@ fn airIsNamedEnumValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7523}7569}
75247570
7525fn airErrorSetHasValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {7571fn airErrorSetHasValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7526 const zcu = cg.pt.zcu;7572 const zcu = cg.zcu;
7527 const ip = &zcu.intern_pool;7573 const ip = &zcu.intern_pool;
7528 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;7574 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
75297575
...@@ -7610,7 +7656,7 @@ inline fn useAtomicFeature(cg: *const CodeGen) bool {...@@ -7610,7 +7656,7 @@ inline fn useAtomicFeature(cg: *const CodeGen) bool {
7610}7656}
76117657
7612fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {7658fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7613 const zcu = cg.pt.zcu;7659 const zcu = cg.zcu;
7614 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;7660 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
7615 const extra = cg.air.extraData(Air.Cmpxchg, ty_pl.payload).data;7661 const extra = cg.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
76167662
...@@ -7636,7 +7682,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7636,7 +7682,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7636 1 => .i32_atomic_rmw8_cmpxchg_u,7682 1 => .i32_atomic_rmw8_cmpxchg_u,
7637 2 => .i32_atomic_rmw16_cmpxchg_u,7683 2 => .i32_atomic_rmw16_cmpxchg_u,
7638 4 => .i32_atomic_rmw_cmpxchg,7684 4 => .i32_atomic_rmw_cmpxchg,
7639 8 => .i32_atomic_rmw_cmpxchg,7685 8 => .i64_atomic_rmw_cmpxchg,
7640 else => |size| return cg.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}),7686 else => |size| return cg.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}),
7641 }, .{7687 }, .{
7642 .offset = ptr_operand.memOffset(),7688 .offset = ptr_operand.memOffset(),
...@@ -7688,7 +7734,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7688,7 +7734,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7688}7734}
76897735
7690fn airAtomicLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {7736fn airAtomicLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7691 const zcu = cg.pt.zcu;7737 const zcu = cg.zcu;
7692 const atomic_load = cg.air.instructions.items(.data)[@backingInt(inst)].atomic_load;7738 const atomic_load = cg.air.instructions.items(.data)[@backingInt(inst)].atomic_load;
7693 const ptr = try cg.resolveInst(atomic_load.ptr);7739 const ptr = try cg.resolveInst(atomic_load.ptr);
7694 const ty = cg.typeOfIndex(inst);7740 const ty = cg.typeOfIndex(inst);
...@@ -7714,7 +7760,7 @@ fn airAtomicLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7714,7 +7760,7 @@ fn airAtomicLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7714}7760}
77157761
7716fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {7762fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7717 const zcu = cg.pt.zcu;7763 const zcu = cg.zcu;
7718 const pl_op = cg.air.instructions.items(.data)[@backingInt(inst)].pl_op;7764 const pl_op = cg.air.instructions.items(.data)[@backingInt(inst)].pl_op;
7719 const extra = cg.air.extraData(Air.AtomicRmw, pl_op.payload).data;7765 const extra = cg.air.extraData(Air.AtomicRmw, pl_op.payload).data;
77207766
...@@ -7724,6 +7770,9 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7724,6 +7770,9 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7724 const op: std.lang.AtomicRmwOp = extra.op();7770 const op: std.lang.AtomicRmwOp = extra.op();
77257771
7726 if (cg.useAtomicFeature()) {7772 if (cg.useAtomicFeature()) {
7773 if (ty.isAnyFloat()) {
7774 return cg.fail("TODO: atomic rmw on floats", .{});
7775 }
7727 const int_ty: IntType = .fromType(cg, ty);7776 const int_ty: IntType = .fromType(cg, ty);
7728 switch (op) {7777 switch (op) {
7729 .Max,7778 .Max,
...@@ -7918,7 +7967,7 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7918,7 +7967,7 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7918}7967}
79197968
7920fn airAtomicStore(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {7969fn airAtomicStore(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7921 const zcu = cg.pt.zcu;7970 const zcu = cg.zcu;
7922 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;7971 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;
79237972
7924 const ptr = try cg.resolveInst(bin_op.lhs);7973 const ptr = try cg.resolveInst(bin_op.lhs);
...@@ -7954,7 +8003,7 @@ fn airFrameAddress(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7954,7 +8003,7 @@ fn airFrameAddress(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
79548003
7955fn airRuntimeNavPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {8004fn airRuntimeNavPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7956 const ty_nav = cg.air.instructions.items(.data)[@backingInt(inst)].ty_nav;8005 const ty_nav = cg.air.instructions.items(.data)[@backingInt(inst)].ty_nav;
7957 const mod = cg.pt.zcu.navFileScope(cg.owner_nav).mod.?;8006 const mod = cg.zcu.navFileScope(cg.owner_nav).mod.?;
7958 if (mod.single_threaded) {8007 if (mod.single_threaded) {
7959 const result: WValue = .{ .nav_ref = .{8008 const result: WValue = .{ .nav_ref = .{
7960 .nav_index = ty_nav.nav,8009 .nav_index = ty_nav.nav,
...@@ -7970,7 +8019,7 @@ fn airAsm(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7970,7 +8019,7 @@ fn airAsm(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7970 const outputs = unwrapped_asm.outputs;8019 const outputs = unwrapped_asm.outputs;
7971 const inputs = unwrapped_asm.inputs;8020 const inputs = unwrapped_asm.inputs;
79728021
7973 const zcu = cg.pt.zcu;8022 const zcu = cg.zcu;
7974 const output_ty = cg.typeOfIndex(inst);8023 const output_ty = cg.typeOfIndex(inst);
79758024
7976 const result: WValue = if (output_ty.hasRuntimeBits(zcu))8025 const result: WValue = if (output_ty.hasRuntimeBits(zcu))
...@@ -8037,11 +8086,11 @@ fn airAsm(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -8037,11 +8086,11 @@ fn airAsm(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
8037}8086}
80388087
8039fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type {8088fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type {
8040 const zcu = cg.pt.zcu;8089 const zcu = cg.zcu;
8041 return cg.air.typeOf(inst, &zcu.intern_pool);8090 return cg.air.typeOf(inst, &zcu.intern_pool);
8042}8091}
80438092
8044fn typeOfIndex(cg: *CodeGen, inst: Air.Inst.Index) Type {8093fn typeOfIndex(cg: *CodeGen, inst: Air.Inst.Index) Type {
8045 const zcu = cg.pt.zcu;8094 const zcu = cg.zcu;
8046 return cg.air.typeOfIndex(inst, &zcu.intern_pool);8095 return cg.air.typeOfIndex(inst, &zcu.intern_pool);
8047}8096}
src/codegen/wasm/Emit.zig+2-2
...@@ -27,7 +27,7 @@ pub fn lower(emit: *Emit) Error!void {...@@ -27,7 +27,7 @@ pub fn lower(emit: *Emit) Error!void {
27 const wasm = emit.wasm;27 const wasm = emit.wasm;
28 const comp = wasm.base.comp;28 const comp = wasm.base.comp;
29 const gpa = comp.gpa;29 const gpa = comp.gpa;
30 const is_obj = comp.config.output_mode == .Obj;30 const is_obj = wasm.base.isRelocatable();
31 const target = &comp.root_mod.resolved_target.result;31 const target = &comp.root_mod.resolved_target.result;
32 const is_wasm32 = target.cpu.arch == .wasm32;32 const is_wasm32 = target.cpu.arch == .wasm32;
3333
...@@ -1028,7 +1028,7 @@ fn navRefOff(wasm: *Wasm, code: *ArrayList(u8), data: Mir.NavRefOff, is_wasm32:...@@ -1028,7 +1028,7 @@ fn navRefOff(wasm: *Wasm, code: *ArrayList(u8), data: Mir.NavRefOff, is_wasm32:
1028 const zcu = comp.zcu.?;1028 const zcu = comp.zcu.?;
1029 const ip = &zcu.intern_pool;1029 const ip = &zcu.intern_pool;
1030 const gpa = comp.gpa;1030 const gpa = comp.gpa;
1031 const is_obj = comp.config.output_mode == .Obj;1031 const is_obj = wasm.base.isRelocatable();
1032 const nav_ty = ip.getNav(data.nav_index).resolved.?.type;1032 const nav_ty = ip.getNav(data.nav_index).resolved.?.type;
1033 assert(!ip.isFunctionType(nav_ty));1033 assert(!ip.isFunctionType(nav_ty));
10341034
src/codegen/x86_64/CodeGen.zig+9-11
...@@ -181803,17 +181803,15 @@ fn intInfo(cg: *CodeGen, ty: Type) ?std.lang.Type.Int {...@@ -181803,17 +181803,15 @@ fn intInfo(cg: *CodeGen, ty: Type) ?std.lang.Type.Int {
181803 .one, .many, .c => .{ .signedness = .unsigned, .bits = cg.target.ptrBitWidth() },181803 .one, .many, .c => .{ .signedness = .unsigned, .bits = cg.target.ptrBitWidth() },
181804 .slice => null,181804 .slice => null,
181805 },181805 },
181806 .opt_type => |opt_child| return if (!Type.fromInterned(opt_child).hasRuntimeBits(zcu))181806 .opt_type => |opt_child| {
181807 .{ .signedness = .unsigned, .bits = 1 }181807 if (!Type.fromInterned(opt_child).hasRuntimeBits(zcu)) {
181808 else switch (ip.indexToKey(opt_child)) {181808 return .{ .signedness = .unsigned, .bits = 1 };
181809 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {181809 }
181810 .one, .many => switch (ptr_type.flags.is_allowzero) {181810 if (Type.fromInterned(ty_index).optionalReprIsPayload(zcu)) {
181811 false => .{ .signedness = .unsigned, .bits = cg.target.ptrBitWidth() },181811 ty_index = opt_child;
181812 true => null,181812 continue;
181813 },181813 }
181814 .slice, .c => null,181814 return null;
181815 },
181816 else => null,
181817 },181815 },
181818 .error_union_type => |error_union_type| return if (!Type.fromInterned(error_union_type.payload_type)181816 .error_union_type => |error_union_type| return if (!Type.fromInterned(error_union_type.payload_type)
181819 .hasRuntimeBits(zcu)) .{ .signedness = .unsigned, .bits = zcu.errorSetBits() } else null,181817 .hasRuntimeBits(zcu)) .{ .signedness = .unsigned, .bits = zcu.errorSetBits() } else null,
src/link/Wasm.zig+48-47
...@@ -79,6 +79,7 @@ growable_table: bool,...@@ -79,6 +79,7 @@ growable_table: bool,
79name: []const u8,79name: []const u8,
80/// List of relocatable files to be linked into the final binary.80/// List of relocatable files to be linked into the final binary.
81objects: std.ArrayList(Object) = .empty,81objects: std.ArrayList(Object) = .empty,
82archive_builder: Archive.Builder = .{},
8283
83func_types: std.array_hash_map.Auto(FunctionType, void) = .empty,84func_types: std.array_hash_map.Auto(FunctionType, void) = .empty,
84/// Provides a mapping of both imports and provided functions to symbol name.85/// Provides a mapping of both imports and provided functions to symbol name.
...@@ -467,8 +468,7 @@ pub const OutputDataIndex = enum(u32) {...@@ -467,8 +468,7 @@ pub const OutputDataIndex = enum(u32) {
467 }468 }
468469
469 pub fn fromUav(wasm: *const Wasm, ip_index: InternPool.Index) OutputDataIndex {470 pub fn fromUav(wasm: *const Wasm, ip_index: InternPool.Index) OutputDataIndex {
470 const comp = wasm.base.comp;471 const resolution: ObjectDataImport.Resolution = if (wasm.base.isRelocatable())
471 const resolution: ObjectDataImport.Resolution = if (comp.config.output_mode == .Obj)
472 .pack(wasm, .{ .uav_obj = @fromBackingInt(@intCast(wasm.uavs_obj.getIndex(ip_index).?)) })472 .pack(wasm, .{ .uav_obj = @fromBackingInt(@intCast(wasm.uavs_obj.getIndex(ip_index).?)) })
473 else473 else
474 .pack(wasm, .{ .uav_exe = @fromBackingInt(@intCast(wasm.uavs_exe.getIndex(ip_index).?)) });474 .pack(wasm, .{ .uav_exe = @fromBackingInt(@intCast(wasm.uavs_exe.getIndex(ip_index).?)) });
...@@ -482,7 +482,7 @@ pub const OutputDataIndex = enum(u32) {...@@ -482,7 +482,7 @@ pub const OutputDataIndex = enum(u32) {
482 if (nav.getExtern(ip) != null) {482 if (nav.getExtern(ip) != null) {
483 return fromSymbolName(wasm, wasm.imports.get(nav_index).?);483 return fromSymbolName(wasm, wasm.imports.get(nav_index).?);
484 }484 }
485 const resolution: ObjectDataImport.Resolution = if (wasm.base.comp.config.output_mode == .Obj)485 const resolution: ObjectDataImport.Resolution = if (wasm.base.isRelocatable())
486 .pack(wasm, .{ .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(nav_index).?)) })486 .pack(wasm, .{ .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(nav_index).?)) })
487 else487 else
488 .pack(wasm, .{ .nav_exe = @fromBackingInt(@intCast(wasm.navs_exe.getIndex(nav_index).?)) });488 .pack(wasm, .{ .nav_exe = @fromBackingInt(@intCast(wasm.navs_exe.getIndex(nav_index).?)) });
...@@ -500,7 +500,7 @@ pub const GlobalIndex = enum(u32) {...@@ -500,7 +500,7 @@ pub const GlobalIndex = enum(u32) {
500 /// Same as `stack_pointer` but with a safety assertion.500 /// Same as `stack_pointer` but with a safety assertion.
501 pub fn stackPointer(wasm: *const Wasm) ObjectGlobal.Index {501 pub fn stackPointer(wasm: *const Wasm) ObjectGlobal.Index {
502 const comp = wasm.base.comp;502 const comp = wasm.base.comp;
503 assert(comp.config.output_mode != .Obj);503 assert(!wasm.base.isRelocatable());
504 assert(comp.zcu != null);504 assert(comp.zcu != null);
505 return .stack_pointer;505 return .stack_pointer;
506 }506 }
...@@ -879,8 +879,7 @@ const ZcuDataStarts = struct {...@@ -879,8 +879,7 @@ const ZcuDataStarts = struct {
879 uavs_i: u32,879 uavs_i: u32,
880880
881 fn init(wasm: *const Wasm) ZcuDataStarts {881 fn init(wasm: *const Wasm) ZcuDataStarts {
882 const comp = wasm.base.comp;882 const is_obj = wasm.base.isRelocatable();
883 const is_obj = comp.config.output_mode == .Obj;
884 return if (is_obj) initObj(wasm) else initExe(wasm);883 return if (is_obj) initObj(wasm) else initExe(wasm);
885 }884 }
886885
...@@ -897,8 +896,7 @@ const ZcuDataStarts = struct {...@@ -897,8 +896,7 @@ const ZcuDataStarts = struct {
897 }896 }
898897
899 fn finish(zds: ZcuDataStarts, wasm: *Wasm, pt: Zcu.PerThread) !void {898 fn finish(zds: ZcuDataStarts, wasm: *Wasm, pt: Zcu.PerThread) !void {
900 const comp = wasm.base.comp;899 const is_obj = wasm.base.isRelocatable();
901 const is_obj = comp.config.output_mode == .Obj;
902 return if (is_obj) finishObj(zds, wasm, pt) else finishExe(zds, wasm, pt);900 return if (is_obj) finishObj(zds, wasm, pt) else finishExe(zds, wasm, pt);
903 }901 }
904902
...@@ -1276,8 +1274,7 @@ pub const GlobalImport = extern struct {...@@ -1276,8 +1274,7 @@ pub const GlobalImport = extern struct {
1276 const object_global_index = i - first_object_global;1274 const object_global_index = i - first_object_global;
1277 if (object_global_index < wasm.object_globals.items.len)1275 if (object_global_index < wasm.object_globals.items.len)
1278 return .{ .object_global = @fromBackingInt(@intCast(object_global_index)) };1276 return .{ .object_global = @fromBackingInt(@intCast(object_global_index)) };
1279 const comp = wasm.base.comp;1277 const is_obj = wasm.base.isRelocatable();
1280 const is_obj = comp.config.output_mode == .Obj;
1281 const uav_index = object_global_index - wasm.object_globals.items.len;1278 const uav_index = object_global_index - wasm.object_globals.items.len;
1282 if (is_obj) {1279 if (is_obj) {
1283 if (uav_index < wasm.uavs_obj.entries.len) {1280 if (uav_index < wasm.uavs_obj.entries.len) {
...@@ -1323,7 +1320,7 @@ pub const GlobalImport = extern struct {...@@ -1323,7 +1320,7 @@ pub const GlobalImport = extern struct {
1323 }1320 }
13241321
1325 pub fn fromIpIndex(wasm: *const Wasm, ip_index: InternPool.Index) Resolution {1322 pub fn fromIpIndex(wasm: *const Wasm, ip_index: InternPool.Index) Resolution {
1326 const is_obj = wasm.base.comp.config.output_mode == .Obj;1323 const is_obj = wasm.base.isRelocatable();
1327 return pack(wasm, if (is_obj) .{1324 return pack(wasm, if (is_obj) .{
1328 .uav_obj = @fromBackingInt(@intCast(wasm.uavs_obj.getIndex(ip_index).?)),1325 .uav_obj = @fromBackingInt(@intCast(wasm.uavs_obj.getIndex(ip_index).?)),
1329 } else .{1326 } else .{
...@@ -1332,8 +1329,7 @@ pub const GlobalImport = extern struct {...@@ -1332,8 +1329,7 @@ pub const GlobalImport = extern struct {
1332 }1329 }
13331330
1334 pub fn fromIpNav(wasm: *const Wasm, ip_nav: InternPool.Nav.Index) Resolution {1331 pub fn fromIpNav(wasm: *const Wasm, ip_nav: InternPool.Nav.Index) Resolution {
1335 const comp = wasm.base.comp;1332 const is_obj = wasm.base.isRelocatable();
1336 const is_obj = comp.config.output_mode == .Obj;
1337 return pack(wasm, if (is_obj) .{1333 return pack(wasm, if (is_obj) .{
1338 .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(ip_nav).?)),1334 .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(ip_nav).?)),
1339 } else .{1335 } else .{
...@@ -1819,8 +1815,7 @@ pub const ObjectDataImport = extern struct {...@@ -1819,8 +1815,7 @@ pub const ObjectDataImport = extern struct {
1819 else1815 else
1820 object_index - wasm.object_datas.items.len;1816 object_index - wasm.object_datas.items.len;
18211817
1822 const comp = wasm.base.comp;1818 const is_obj = wasm.base.isRelocatable();
1823 const is_obj = comp.config.output_mode == .Obj;
1824 if (is_obj) {1819 if (is_obj) {
1825 const nav_index = if (uav_index < wasm.uavs_obj.entries.len)1820 const nav_index = if (uav_index < wasm.uavs_obj.entries.len)
1826 return .{ .uav_obj = @fromBackingInt(@intCast(uav_index)) }1821 return .{ .uav_obj = @fromBackingInt(@intCast(uav_index)) }
...@@ -1863,7 +1858,7 @@ pub const ObjectDataImport = extern struct {...@@ -1863,7 +1858,7 @@ pub const ObjectDataImport = extern struct {
1863 }1858 }
18641859
1865 pub fn fromIpIndex(wasm: *const Wasm, ip_index: InternPool.Index) Resolution {1860 pub fn fromIpIndex(wasm: *const Wasm, ip_index: InternPool.Index) Resolution {
1866 const is_obj = wasm.base.comp.config.output_mode == .Obj;1861 const is_obj = wasm.base.isRelocatable();
1867 return pack(wasm, if (is_obj) .{1862 return pack(wasm, if (is_obj) .{
1868 .uav_obj = @fromBackingInt(@intCast(wasm.uavs_obj.getIndex(ip_index).?)),1863 .uav_obj = @fromBackingInt(@intCast(wasm.uavs_obj.getIndex(ip_index).?)),
1869 } else .{1864 } else .{
...@@ -1872,7 +1867,7 @@ pub const ObjectDataImport = extern struct {...@@ -1872,7 +1867,7 @@ pub const ObjectDataImport = extern struct {
1872 }1867 }
18731868
1874 pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) Resolution {1869 pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) Resolution {
1875 const is_obj = wasm.base.comp.config.output_mode == .Obj;1870 const is_obj = wasm.base.isRelocatable();
1876 return pack(wasm, if (is_obj) .{1871 return pack(wasm, if (is_obj) .{
1877 .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(nav_index).?)),1872 .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(nav_index).?)),
1878 } else .{1873 } else .{
...@@ -2117,8 +2112,7 @@ pub const DataSegmentId = enum(u32) {...@@ -2117,8 +2112,7 @@ pub const DataSegmentId = enum(u32) {
2117 else2112 else
2118 object_index - wasm.object_data_segments.items.len;2113 object_index - wasm.object_data_segments.items.len;
21192114
2120 const comp = wasm.base.comp;2115 const is_obj = wasm.base.isRelocatable();
2121 const is_obj = comp.config.output_mode == .Obj;
2122 if (is_obj) {2116 if (is_obj) {
2123 const nav_index = if (uav_index < wasm.uavs_obj.entries.len)2117 const nav_index = if (uav_index < wasm.uavs_obj.entries.len)
2124 return .{ .uav_obj = @fromBackingInt(@intCast(uav_index)) }2118 return .{ .uav_obj = @fromBackingInt(@intCast(uav_index)) }
...@@ -2139,8 +2133,7 @@ pub const DataSegmentId = enum(u32) {...@@ -2139,8 +2133,7 @@ pub const DataSegmentId = enum(u32) {
2139 }2133 }
21402134
2141 pub fn fromNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) DataSegmentId {2135 pub fn fromNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) DataSegmentId {
2142 const comp = wasm.base.comp;2136 const is_obj = wasm.base.isRelocatable();
2143 const is_obj = comp.config.output_mode == .Obj;
2144 return pack(wasm, if (is_obj) .{2137 return pack(wasm, if (is_obj) .{
2145 .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(nav_index).?)),2138 .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(nav_index).?)),
2146 } else .{2139 } else .{
...@@ -2717,17 +2710,17 @@ pub const FunctionImportId = enum(u32) {...@@ -2717,17 +2710,17 @@ pub const FunctionImportId = enum(u32) {
2717 /// Asserts not emitting an object, and `Wasm.import_symbols` is false.2710 /// Asserts not emitting an object, and `Wasm.import_symbols` is false.
2718 pub fn undefinedAllowed(id: FunctionImportId, wasm: *const Wasm) bool {2711 pub fn undefinedAllowed(id: FunctionImportId, wasm: *const Wasm) bool {
2719 assert(!wasm.import_symbols);2712 assert(!wasm.import_symbols);
2720 assert(wasm.base.comp.config.output_mode != .Obj);2713 assert(!wasm.base.isRelocatable());
2721 return switch (unpack(id, wasm)) {2714 return switch (unpack(id, wasm)) {
2722 .object_function_import => |i| {2715 .object_function_import => |i| {
2723 const import = i.value(wasm);2716 const import = i.value(wasm);
2724 return import.flags.binding == .strong and import.module_name != .none;2717 return import.flags.binding == .strong;
2725 },2718 },
2726 .zcu_import => |i| {2719 .zcu_import => |i| {
2727 const zcu = wasm.base.comp.zcu.?;2720 const zcu = wasm.base.comp.zcu.?;
2728 const ip = &zcu.intern_pool;2721 const ip = &zcu.intern_pool;
2729 const ext = ip.indexToKey(ip.getNav(i.ptr(wasm).*).resolved.?.value).@"extern";2722 const ext = ip.indexToKey(ip.getNav(i.ptr(wasm).*).resolved.?.value).@"extern";
2730 return ext.linkage != .weak and ext.lib_name != .none;2723 return ext.linkage == .strong;
2731 },2724 },
2732 };2725 };
2733 }2726 }
...@@ -3343,6 +3336,7 @@ pub fn createEmpty(...@@ -3343,6 +3336,7 @@ pub fn createEmpty(
3343 assert(target.ofmt == .wasm);3336 assert(target.ofmt == .wasm);
33443337
3345 const output_mode = comp.config.output_mode;3338 const output_mode = comp.config.output_mode;
3339 const is_relocatable = output_mode == .Obj or (output_mode == .Lib and comp.config.link_mode == .static);
3346 const wasi_exec_model = comp.config.wasi_exec_model;3340 const wasi_exec_model = comp.config.wasi_exec_model;
33473341
3348 const wasm = try arena.create(Wasm);3342 const wasm = try arena.create(Wasm);
...@@ -3356,7 +3350,7 @@ pub fn createEmpty(...@@ -3356,7 +3350,7 @@ pub fn createEmpty(
3356 // majority of cases, and therefore express "no garbage collection"3350 // majority of cases, and therefore express "no garbage collection"
3357 // in terms of setting the no_strip and must_link flags on all3351 // in terms of setting the no_strip and must_link flags on all
3358 // symbols.3352 // symbols.
3359 .gc_sections = options.gc_sections orelse (output_mode != .Obj),3353 .gc_sections = options.gc_sections orelse !is_relocatable,
3360 .print_gc_sections = options.print_gc_sections,3354 .print_gc_sections = options.print_gc_sections,
3361 .stack_size = options.stack_size orelse switch (target.os.tag) {3355 .stack_size = options.stack_size orelse switch (target.os.tag) {
3362 .freestanding => 1 * 1024 * 1024, // 1 MiB3356 .freestanding => 1 * 1024 * 1024, // 1 MiB
...@@ -3436,6 +3430,11 @@ fn parseObject(wasm: *Wasm, obj: link.Input.Object) !void {...@@ -3436,6 +3430,11 @@ fn parseObject(wasm: *Wasm, obj: link.Input.Object) !void {
3436 };3430 };
3437 if (n != file_contents.len) return error.UnexpectedEndOfFile;3431 if (n != file_contents.len) return error.UnexpectedEndOfFile;
34383432
3433 if (wasm.base.isStaticLib()) {
3434 try wasm.archive_builder.append(gpa, std.fs.path.basename(obj.path.sub_path), file_contents);
3435 return;
3436 }
3437
3439 var ss: Object.ScratchSpace = .{};3438 var ss: Object.ScratchSpace = .{};
3440 defer ss.deinit(gpa);3439 defer ss.deinit(gpa);
34413440
...@@ -3526,6 +3525,7 @@ pub fn deinit(wasm: *Wasm) void {...@@ -3526,6 +3525,7 @@ pub fn deinit(wasm: *Wasm) void {
3526 wasm.object_relocations_table.deinit(gpa);3525 wasm.object_relocations_table.deinit(gpa);
3527 wasm.object_comdat_symbols.deinit(gpa);3526 wasm.object_comdat_symbols.deinit(gpa);
3528 wasm.objects.deinit(gpa);3527 wasm.objects.deinit(gpa);
3528 wasm.archive_builder.deinit(gpa);
35293529
3530 wasm.func_types.deinit(gpa);3530 wasm.func_types.deinit(gpa);
3531 wasm.function_exports.deinit(gpa);3531 wasm.function_exports.deinit(gpa);
...@@ -3575,7 +3575,7 @@ pub fn updateFunc(...@@ -3575,7 +3575,7 @@ pub fn updateFunc(
3575 const zcu = pt.zcu;3575 const zcu = pt.zcu;
3576 const gpa = zcu.gpa;3576 const gpa = zcu.gpa;
3577 const ip = &zcu.intern_pool;3577 const ip = &zcu.intern_pool;
3578 const is_obj = zcu.comp.config.output_mode == .Obj;3578 const is_obj = wasm.base.isRelocatable();
3579 const target = &zcu.comp.root_mod.resolved_target.result;3579 const target = &zcu.comp.root_mod.resolved_target.result;
3580 const owner_nav = zcu.funcInfo(func_index).owner_nav;3580 const owner_nav = zcu.funcInfo(func_index).owner_nav;
3581 log.debug("updateFunc {f}", .{ip.getNav(owner_nav).fqn.fmt(ip)});3581 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...@@ -3656,7 +3656,7 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
3656 const nav = ip.getNav(nav_index);3656 const nav = ip.getNav(nav_index);
3657 const comp = wasm.base.comp;3657 const comp = wasm.base.comp;
3658 const gpa = comp.gpa;3658 const gpa = comp.gpa;
3659 const is_obj = comp.config.output_mode == .Obj;3659 const is_obj = wasm.base.isRelocatable();
3660 const target = &comp.root_mod.resolved_target.result;3660 const target = &comp.root_mod.resolved_target.result;
36613661
3662 switch (ip.indexToKey(nav.resolved.?.value)) {3662 switch (ip.indexToKey(nav.resolved.?.value)) {
...@@ -3740,7 +3740,7 @@ pub fn updateExports(...@@ -3740,7 +3740,7 @@ pub fn updateExports(
3740 const zcu = pt.zcu;3740 const zcu = pt.zcu;
3741 const gpa = zcu.gpa;3741 const gpa = zcu.gpa;
3742 const ip = &zcu.intern_pool;3742 const ip = &zcu.intern_pool;
3743 const is_obj = wasm.base.comp.config.output_mode == .Obj;3743 const is_obj = wasm.base.isRelocatable();
37443744
3745 for (export_indices) |export_idx| {3745 for (export_indices) |export_idx| {
3746 const exp = export_idx.ptr(zcu);3746 const exp = export_idx.ptr(zcu);
...@@ -3797,7 +3797,11 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void {...@@ -3797,7 +3797,11 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void {
3797 .dso => unreachable,3797 .dso => unreachable,
3798 .tbd => unreachable,3798 .tbd => unreachable,
3799 .object => |obj| try parseObject(wasm, obj),3799 .object => |obj| try parseObject(wasm, obj),
3800 .archive => |obj| try parseArchive(wasm, obj),3800 .archive => |obj| if (wasm.base.isStaticLib()) {
3801 obj.file.close(io); // ignore archives like LLVM
3802 } else {
3803 try parseArchive(wasm, obj);
3804 },
3801 }3805 }
3802}3806}
38033807
...@@ -3811,7 +3815,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.Error!void {...@@ -3811,7 +3815,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.Error!void {
3811 const comp = wasm.base.comp;3815 const comp = wasm.base.comp;
3812 const gpa = comp.gpa;3816 const gpa = comp.gpa;
3813 const rdynamic = comp.config.rdynamic;3817 const rdynamic = comp.config.rdynamic;
3814 const is_obj = comp.config.output_mode == .Obj;3818 const is_obj = wasm.base.isRelocatable();
38153819
3816 assert(wasm.missing_exports.entries.len == 0);3820 assert(wasm.missing_exports.entries.len == 0);
3817 for (wasm.export_symbol_names) |exp_name| {3821 for (wasm.export_symbol_names) |exp_name| {
...@@ -3915,7 +3919,7 @@ pub fn markFunctionImport(...@@ -3915,7 +3919,7 @@ pub fn markFunctionImport(
39153919
3916 const comp = wasm.base.comp;3920 const comp = wasm.base.comp;
3917 const gpa = comp.gpa;3921 const gpa = comp.gpa;
3918 const is_obj = comp.config.output_mode == .Obj;3922 const is_obj = wasm.base.isRelocatable();
39193923
3920 try wasm.functions.ensureUnusedCapacity(gpa, 1);3924 try wasm.functions.ensureUnusedCapacity(gpa, 1);
39213925
...@@ -3949,7 +3953,7 @@ fn markFunction(wasm: *Wasm, i: ObjectFunctionIndex, override_export: bool) link...@@ -3949,7 +3953,7 @@ fn markFunction(wasm: *Wasm, i: ObjectFunctionIndex, override_export: bool) link
3949 if (gop.found_existing) return;3953 if (gop.found_existing) return;
39503954
3951 const rdynamic = comp.config.rdynamic;3955 const rdynamic = comp.config.rdynamic;
3952 const is_obj = comp.config.output_mode == .Obj;3956 const is_obj = wasm.base.isRelocatable();
3953 const function = i.ptr(wasm);3957 const function = i.ptr(wasm);
3954 try markObject(wasm, function.object_index);3958 try markObject(wasm, function.object_index);
39553959
...@@ -3991,7 +3995,7 @@ fn markGlobalImport(...@@ -3991,7 +3995,7 @@ fn markGlobalImport(
39913995
3992 const comp = wasm.base.comp;3996 const comp = wasm.base.comp;
3993 const gpa = comp.gpa;3997 const gpa = comp.gpa;
3994 const is_obj = comp.config.output_mode == .Obj;3998 const is_obj = wasm.base.isRelocatable();
39953999
3996 try wasm.globals.ensureUnusedCapacity(gpa, 1);4000 try wasm.globals.ensureUnusedCapacity(gpa, 1);
39974001
...@@ -4034,7 +4038,7 @@ fn markGlobal(wasm: *Wasm, i: ObjectGlobalIndex, override_export: bool) link.Err...@@ -4034,7 +4038,7 @@ fn markGlobal(wasm: *Wasm, i: ObjectGlobalIndex, override_export: bool) link.Err
4034 if (gop.found_existing) return;4038 if (gop.found_existing) return;
40354039
4036 const rdynamic = comp.config.rdynamic;4040 const rdynamic = comp.config.rdynamic;
4037 const is_obj = comp.config.output_mode == .Obj;4041 const is_obj = wasm.base.isRelocatable();
4038 const global = i.ptr(wasm);4042 const global = i.ptr(wasm);
4039 try markObject(wasm, global.object_index);4043 try markObject(wasm, global.object_index);
40404044
...@@ -4057,7 +4061,7 @@ pub fn markTableImport(...@@ -4057,7 +4061,7 @@ pub fn markTableImport(
40574061
4058 const comp = wasm.base.comp;4062 const comp = wasm.base.comp;
4059 const gpa = comp.gpa;4063 const gpa = comp.gpa;
4060 const is_obj = comp.config.output_mode == .Obj;4064 const is_obj = wasm.base.isRelocatable();
40614065
4062 try wasm.tables.ensureUnusedCapacity(gpa, 1);4066 try wasm.tables.ensureUnusedCapacity(gpa, 1);
40634067
...@@ -4103,7 +4107,7 @@ pub fn markDataImport(...@@ -4103,7 +4107,7 @@ pub fn markDataImport(
41034107
4104 const comp = wasm.base.comp;4108 const comp = wasm.base.comp;
4105 const gpa = comp.gpa;4109 const gpa = comp.gpa;
4106 const is_obj = comp.config.output_mode == .Obj;4110 const is_obj = wasm.base.isRelocatable();
41074111
4108 if (import.resolution == .unresolved) {4112 if (import.resolution == .unresolved) {
4109 if (!is_obj) {4113 if (!is_obj) {
...@@ -4682,7 +4686,7 @@ pub fn addNavReloc(...@@ -4682,7 +4686,7 @@ pub fn addNavReloc(
4682 const ip = &zcu.intern_pool;4686 const ip = &zcu.intern_pool;
4683 const gpa = comp.gpa;4687 const gpa = comp.gpa;
46844688
4685 const is_obj = comp.config.output_mode == .Obj;4689 const is_obj = wasm.base.isRelocatable();
46864690
4687 if (nav_ty.zigTypeTag(zcu) == .@"fn") {4691 if (nav_ty.zigTypeTag(zcu) == .@"fn") {
4688 const gop = try wasm.zcu_indirect_function_set.getOrPut(gpa, nav_index);4692 const gop = try wasm.zcu_indirect_function_set.getOrPut(gpa, nav_index);
...@@ -4751,7 +4755,7 @@ pub fn addUavReloc(...@@ -4751,7 +4755,7 @@ pub fn addUavReloc(
4751 gop.value_ptr.* = if (gop.found_existing) gop.value_ptr.maxStrict(this_align) else this_align;4755 gop.value_ptr.* = if (gop.found_existing) gop.value_ptr.maxStrict(this_align) else this_align;
4752 }4756 }
47534757
4754 if (comp.config.output_mode == .Obj) {4758 if (wasm.base.isRelocatable()) {
4755 const gop = try wasm.uavs_obj.getOrPut(gpa, uav_val);4759 const gop = try wasm.uavs_obj.getOrPut(gpa, uav_val);
4756 if (!gop.found_existing) gop.value_ptr.* = undefined; // to avoid recursion, `ZcuDataStarts` will lower the value later4760 if (!gop.found_existing) gop.value_ptr.* = undefined; // to avoid recursion, `ZcuDataStarts` will lower the value later
4757 try wasm.zcu_relocations.append(gpa, .{4761 try wasm.zcu_relocations.append(gpa, .{
...@@ -4782,7 +4786,7 @@ pub fn addUavReloc(...@@ -4782,7 +4786,7 @@ pub fn addUavReloc(
4782pub fn refNavObj(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsObjIndex {4786pub fn refNavObj(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsObjIndex {
4783 const comp = wasm.base.comp;4787 const comp = wasm.base.comp;
4784 const gpa = comp.gpa;4788 const gpa = comp.gpa;
4785 assert(comp.config.output_mode == .Obj);4789 assert(wasm.base.isRelocatable());
4786 const gop = try wasm.navs_obj.getOrPut(gpa, nav_index);4790 const gop = try wasm.navs_obj.getOrPut(gpa, nav_index);
4787 if (!gop.found_existing) gop.value_ptr.* = .{4791 if (!gop.found_existing) gop.value_ptr.* = .{
4788 // Lowering the value is delayed to avoid recursion.4792 // Lowering the value is delayed to avoid recursion.
...@@ -4795,7 +4799,7 @@ pub fn refNavObj(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsObjIndex {...@@ -4795,7 +4799,7 @@ pub fn refNavObj(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsObjIndex {
4795pub fn refNavExe(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsExeIndex {4799pub fn refNavExe(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsExeIndex {
4796 const comp = wasm.base.comp;4800 const comp = wasm.base.comp;
4797 const gpa = comp.gpa;4801 const gpa = comp.gpa;
4798 assert(comp.config.output_mode != .Obj);4802 assert(!wasm.base.isRelocatable());
4799 const gop = try wasm.navs_exe.getOrPut(gpa, nav_index);4803 const gop = try wasm.navs_exe.getOrPut(gpa, nav_index);
4800 if (gop.found_existing) {4804 if (gop.found_existing) {
4801 gop.value_ptr.count += 1;4805 gop.value_ptr.count += 1;
...@@ -4812,8 +4816,7 @@ pub fn refNavExe(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsExeIndex {...@@ -4812,8 +4816,7 @@ pub fn refNavExe(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsExeIndex {
4812/// Asserts it is called after `Flush.data_segments` is fully populated and sorted.4816/// Asserts it is called after `Flush.data_segments` is fully populated and sorted.
4813pub fn uavAddr(wasm: *const Wasm, ip_index: InternPool.Index) u32 {4817pub fn uavAddr(wasm: *const Wasm, ip_index: InternPool.Index) u32 {
4814 assert(wasm.flush_buffer.memory_layout_finished);4818 assert(wasm.flush_buffer.memory_layout_finished);
4815 const comp = wasm.base.comp;4819 assert(!wasm.base.isRelocatable());
4816 assert(comp.config.output_mode != .Obj);
4817 const uav_index: UavsExeIndex = @fromBackingInt(@intCast(wasm.uavs_exe.getIndex(ip_index).?));4820 const uav_index: UavsExeIndex = @fromBackingInt(@intCast(wasm.uavs_exe.getIndex(ip_index).?));
4818 const ds_id: DataSegmentId = .pack(wasm, .{ .uav_exe = uav_index });4821 const ds_id: DataSegmentId = .pack(wasm, .{ .uav_exe = uav_index });
4819 return wasm.flush_buffer.data_segments.get(ds_id).?;4822 return wasm.flush_buffer.data_segments.get(ds_id).?;
...@@ -4834,7 +4837,7 @@ pub fn syntheticDataAddr(wasm: *const Wasm, resolution: ObjectDataImport.Resolut...@@ -4834,7 +4837,7 @@ pub fn syntheticDataAddr(wasm: *const Wasm, resolution: ObjectDataImport.Resolut
4834pub fn navAddr(wasm: *const Wasm, nav_index: InternPool.Nav.Index) u32 {4837pub fn navAddr(wasm: *const Wasm, nav_index: InternPool.Nav.Index) u32 {
4835 assert(wasm.flush_buffer.memory_layout_finished);4838 assert(wasm.flush_buffer.memory_layout_finished);
4836 const comp = wasm.base.comp;4839 const comp = wasm.base.comp;
4837 assert(comp.config.output_mode != .Obj);4840 assert(!wasm.base.isRelocatable());
4838 if (wasm.navs_exe.getIndex(nav_index)) |i| {4841 if (wasm.navs_exe.getIndex(nav_index)) |i| {
4839 const navs_exe_index: NavsExeIndex = @fromBackingInt(@intCast(i));4842 const navs_exe_index: NavsExeIndex = @fromBackingInt(@intCast(i));
4840 log.debug("navAddr {s} {}", .{ navs_exe_index.name(wasm), nav_index });4843 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 {...@@ -4888,15 +4891,13 @@ pub fn navAddr(wasm: *const Wasm, nav_index: InternPool.Nav.Index) u32 {
4888/// Asserts it is called after `Flush.data_segments` is fully populated and sorted.4891/// Asserts it is called after `Flush.data_segments` is fully populated and sorted.
4889pub fn errorNameTableAddr(wasm: *Wasm) u32 {4892pub fn errorNameTableAddr(wasm: *Wasm) u32 {
4890 assert(wasm.flush_buffer.memory_layout_finished);4893 assert(wasm.flush_buffer.memory_layout_finished);
4891 const comp = wasm.base.comp;4894 assert(!wasm.base.isRelocatable());
4892 assert(comp.config.output_mode != .Obj);
4893 return wasm.flush_buffer.data_segments.get(.__zig_error_name_table).?;4895 return wasm.flush_buffer.data_segments.get(.__zig_error_name_table).?;
4894}4896}
48954897
4896pub fn tagIndexTableAddr(wasm: *Wasm, ip_index: InternPool.Index) u32 {4898pub fn tagIndexTableAddr(wasm: *Wasm, ip_index: InternPool.Index) u32 {
4897 assert(wasm.flush_buffer.memory_layout_finished);4899 assert(wasm.flush_buffer.memory_layout_finished);
4898 const comp = wasm.base.comp;4900 assert(!wasm.base.isRelocatable());
4899 assert(comp.config.output_mode != .Obj);
4900 const f = &wasm.flush_buffer;4901 const f = &wasm.flush_buffer;
4901 const table_base_addr = f.data_segments.get(.__zig_tag_name_table).?;4902 const table_base_addr = f.data_segments.get(.__zig_tag_name_table).?;
4902 return table_base_addr + wasm.tagIndexTableOffset(ip_index);4903 return table_base_addr + wasm.tagIndexTableOffset(ip_index);
src/link/Wasm/Archive.zig+138
...@@ -68,6 +68,143 @@ const Header = extern struct {...@@ -68,6 +68,143 @@ const Header = extern struct {
68 }68 }
69};69};
7070
71pub const Builder = struct {
72 file_names: std.ArrayList(u8) = .empty,
73 members: std.ArrayList(u8) = .empty,
74 symbol_names: std.ArrayList(u8) = .empty,
75 symbol_offsets: std.ArrayList(u32) = .empty,
76
77 pub fn deinit(b: *Builder, gpa: Allocator) void {
78 b.file_names.deinit(gpa);
79 b.members.deinit(gpa);
80 b.symbol_names.deinit(gpa);
81 b.symbol_offsets.deinit(gpa);
82 b.* = undefined;
83 }
84
85 pub fn append(b: *Builder, gpa: Allocator, name: []const u8, data: []const u8) !void {
86 const member_offset: u32 = @intCast(b.members.items.len);
87 const name_offset = b.file_names.items.len;
88
89 try b.file_names.appendSlice(gpa, name);
90 try b.file_names.appendSlice(gpa, "/\n");
91
92 var name_buf: [16]u8 = undefined;
93 const header_name = try std.mem.print(&name_buf, "/{d}", .{name_offset});
94 const member_size = @sizeOf(Header) + mem.alignForward(usize, data.len, 2);
95 var w: std.Io.Writer = .fixed(try b.members.addManyAsSlice(gpa, member_size));
96 try writeHeader(&w, header_name, data.len);
97 try w.writeAll(data);
98 if (data.len % 2 != 0) try w.writeByte('\n');
99
100 try b.collectSymbols(gpa, data, member_offset);
101 }
102
103 pub fn write(b: *Builder, w: *std.Io.Writer) std.Io.Writer.Error!void {
104 const symtab_size = 4 + 4 * b.symbol_offsets.items.len + b.symbol_names.items.len;
105 const members_offset = ARMAG.len + @sizeOf(Header) + mem.alignForward(usize, symtab_size, 2) +
106 @sizeOf(Header) + mem.alignForward(usize, b.file_names.items.len, 2);
107
108 try w.writeAll(ARMAG);
109
110 try writeHeader(w, "/", symtab_size);
111 try w.writeInt(u32, @intCast(b.symbol_offsets.items.len), .big);
112 for (b.symbol_offsets.items) |offset| try w.writeInt(u32, @intCast(members_offset + offset), .big);
113 try w.writeAll(b.symbol_names.items);
114 if (symtab_size % 2 != 0) try w.writeByte('\n');
115
116 try writeHeader(w, "//", b.file_names.items.len);
117 try w.writeAll(b.file_names.items);
118 if (b.file_names.items.len % 2 != 0) try w.writeByte('\n');
119
120 try w.writeAll(b.members.items);
121 }
122
123 fn collectSymbols(b: *Builder, gpa: Allocator, data: []const u8, member_offset: u32) !void {
124 var reader: std.Io.Reader = .fixed(data);
125 if (!mem.eql(u8, try reader.take(4), &std.wasm.magic)) return error.BadObjectMagic;
126 if (!mem.eql(u8, try reader.take(4), &std.wasm.version)) return error.UnsupportedVersion;
127
128 while (reader.seek < data.len) {
129 const section_tag = try reader.takeEnum(std.wasm.Section, .little);
130 const section_len = try reader.takeLeb128(u32);
131 var section: std.Io.Reader = .fixed(try reader.take(section_len));
132 if (section_tag != .custom) continue;
133
134 const section_name = try readBytes(&section);
135 if (mem.eql(u8, section_name, "linking")) {
136 const section_version = try section.takeLeb128(u32);
137 if (section_version != 2) return error.UnsupportedVersion;
138
139 while (section.seek < section.buffer.len) {
140 const sub_type = try section.takeLeb128(u8);
141 const payload_len = try section.takeLeb128(u32);
142
143 var symtab: std.Io.Reader = .fixed(try section.take(payload_len));
144 if (sub_type != @backingInt(Object.SubsectionType.symbol_table)) continue;
145
146 const count = try symtab.takeLeb128(u32);
147 for (0..count) |_| {
148 const tag = try symtab.takeEnum(Object.Symbol.Tag, .little);
149 const flags = try symtab.takeLeb128(u32);
150 const symbol_flags: Wasm.SymbolFlags = @bitCast(flags);
151
152 var name: []const u8 = undefined;
153 switch (tag) {
154 .data => {
155 name = try readBytes(&symtab);
156 if (!symbol_flags.undefined) {
157 _ = try symtab.takeLeb128(u32);
158 _ = try symtab.takeLeb128(u64);
159 _ = try symtab.takeLeb128(u64);
160 }
161 },
162 .section => {
163 _ = try symtab.takeLeb128(u32);
164 continue;
165 },
166 .function, .global, .event, .table => {
167 _ = try symtab.takeLeb128(u32);
168 if (!symbol_flags.undefined or symbol_flags.explicit_name) {
169 name = try readBytes(&symtab);
170 }
171 },
172 }
173
174 if (!symbol_flags.undefined and symbol_flags.binding != .local) {
175 try b.symbol_names.appendSlice(gpa, name);
176 try b.symbol_names.append(gpa, 0);
177 try b.symbol_offsets.append(gpa, member_offset);
178 }
179 }
180 }
181 return;
182 }
183 }
184 return error.MissingLinkingSection;
185 }
186};
187
188fn writeHeader(w: *std.Io.Writer, name: []const u8, size: usize) std.Io.Writer.Error!void {
189 var header: Header = .{
190 .name = @splat(' '),
191 .date = "0 ".*,
192 .uid = "0 ".*,
193 .gid = "0 ".*,
194 .mode = "644 ".*,
195 .size = @splat(' '),
196 .fmag = ARFMAG.*,
197 };
198 @memcpy(header.name[0..name.len], name);
199 _ = std.mem.print(&header.size, "{d}", .{size}) catch unreachable;
200 try w.writeAll(mem.asBytes(&header));
201}
202
203fn readBytes(reader: *std.Io.Reader) ![]const u8 {
204 const len = try reader.takeLeb128(u32);
205 return reader.take(len);
206}
207
71pub fn deinit(archive: *Archive, gpa: Allocator) void {208pub fn deinit(archive: *Archive, gpa: Allocator) void {
72 deinitToc(gpa, &archive.toc);209 deinitToc(gpa, &archive.toc);
73 archive.* = undefined;210 archive.* = undefined;
...@@ -102,6 +239,7 @@ pub fn parse(gpa: Allocator, file_contents: []const u8) !Archive {...@@ -102,6 +239,7 @@ pub fn parse(gpa: Allocator, file_contents: []const u8) !Archive {
102239
103 const sym_tab = file_contents[pos..][0 .. sym_tab_size - 4 - symbol_positions_size];240 const sym_tab = file_contents[pos..][0 .. sym_tab_size - 4 - symbol_positions_size];
104 pos += sym_tab.len;241 pos += sym_tab.len;
242 pos = mem.alignForward(usize, pos, 2);
105243
106 var toc: Toc = .empty;244 var toc: Toc = .empty;
107 errdefer deinitToc(gpa, &toc);245 errdefer deinitToc(gpa, &toc);
src/link/Wasm/Flush.zig+27-4
...@@ -247,7 +247,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -247,7 +247,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
247 .wasm64 => true,247 .wasm64 => true,
248 else => unreachable,248 else => unreachable,
249 };249 };
250 const is_obj = comp.config.output_mode == .Obj;250 const is_obj = wasm.base.isRelocatable();
251 const allow_undefined = is_obj or wasm.import_symbols;251 const allow_undefined = is_obj or wasm.import_symbols;
252 const zcu_references = if (comp.zcu) |zcu| try zcu.resolveReferences() else null;252 const zcu_references = if (comp.zcu) |zcu| try zcu.resolveReferences() else null;
253253
...@@ -1725,9 +1725,32 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -1725,9 +1725,32 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
17251725
1726 // Finally, write the entire binary into the file.1726 // Finally, write the entire binary into the file.
1727 var file_writer = wasm.base.file.?.writer(io, &.{});1727 var file_writer = wasm.base.file.?.writer(io, &.{});
1728 file_writer.interface.writeAll(binary_bytes.items) catch |err| switch (err) {1728 if (wasm.base.isStaticLib()) {
1729 error.WriteFailed => return file_writer.err.?,1729 const builder = &wasm.archive_builder;
1730 };1730 // restore for incremental
1731 const file_names_len = builder.file_names.items.len;
1732 defer builder.file_names.shrinkRetainingCapacity(file_names_len);
1733 const members_len = builder.members.items.len;
1734 defer builder.members.shrinkRetainingCapacity(members_len);
1735 const symbol_names_len = builder.symbol_names.items.len;
1736 defer builder.symbol_names.shrinkRetainingCapacity(symbol_names_len);
1737 const symbol_offsets_len = builder.symbol_offsets.items.len;
1738 defer builder.symbol_offsets.shrinkRetainingCapacity(symbol_offsets_len);
1739
1740 // TODO: pass ZCU data and symbols to write, so reparsing not needed
1741 if (comp.zcu != null) {
1742 const name = try std.fmt.allocPrint(gpa, "{s}_zcu.o", .{comp.root_name});
1743 defer gpa.free(name);
1744 try builder.append(gpa, name, binary_bytes.items);
1745 }
1746 builder.write(&file_writer.interface) catch |err| switch (err) {
1747 error.WriteFailed => return file_writer.err.?,
1748 };
1749 } else {
1750 file_writer.interface.writeAll(binary_bytes.items) catch |err| switch (err) {
1751 error.WriteFailed => return file_writer.err.?,
1752 };
1753 }
1731 file_writer.end() catch |err| switch (err) {1754 file_writer.end() catch |err| switch (err) {
1732 error.WriteFailed => return file_writer.err.?,1755 error.WriteFailed => return file_writer.err.?,
1733 else => |e| return e,1756 else => |e| return e,
test/behavior/atomics.zig+1
...@@ -184,6 +184,7 @@ fn testAtomicStore() !void {...@@ -184,6 +184,7 @@ fn testAtomicStore() !void {
184}184}
185185
186test "atomicrmw with floats" {186test "atomicrmw with floats" {
187 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
187 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
188 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO189 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
189 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO190 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/optional.zig+34
...@@ -58,6 +58,40 @@ fn testNullPtrsEql() !void {...@@ -58,6 +58,40 @@ fn testNullPtrsEql() !void {
58 try expect(&number == x);58 try expect(&number == x);
59}59}
6060
61test "optional error equality" {
62 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
63 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
64 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
65 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
66 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
67
68 const S = struct {
69 fn testEql(comptime T: type, a: ?T, b: ?T, equal: bool) !void {
70 try expect((a == b) == equal);
71 try expect((a != b) == !equal);
72 }
73
74 fn doTheTest() !void {
75 try testEql(error{}, null, null, true);
76
77 try testEql(error{ A, B }, null, null, true);
78 try testEql(error{ A, B }, error.A, error.A, true);
79 try testEql(error{ A, B }, error.A, error.B, false);
80 try testEql(error{ A, B }, null, error.A, false);
81 try testEql(error{ A, B }, error.A, null, false);
82
83 try testEql(anyerror, null, null, true);
84 try testEql(anyerror, error.A, error.A, true);
85 try testEql(anyerror, error.A, error.B, false);
86 try testEql(anyerror, null, error.A, false);
87 try testEql(anyerror, error.A, null, false);
88 }
89 };
90
91 try S.doTheTest();
92 try comptime S.doTheTest();
93}
94
61test "optional with zero-bit type" {95test "optional with zero-bit type" {
62 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;96 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
63 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;97 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/switch.zig+125-23
...@@ -47,34 +47,136 @@ test "switch arbitrary int size" {...@@ -47,34 +47,136 @@ test "switch arbitrary int size" {
47 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO47 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO48 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
4949
50 try expect(testSwitchArbInt(u64, 0) == 0);50 const S = struct {
51 try expect(testSwitchArbInt(u64, 12) == 1);51 fn testSwitchArbInt(comptime T: type, x: T) u32 {
52 try expect(testSwitchArbInt(u64, maxInt(u64)) == 2);52 return switch (x) {
53 try expect(testSwitchArbInt(u64, 5555) == 3);53 minInt(T) => 0,
5454 10...15 => 1,
55 try expect(testSwitchArbInt(i64, minInt(i64)) == 0);55 maxInt(T) => 2,
56 try expect(testSwitchArbInt(i64, 12) == 1);56 else => 3,
57 try expect(testSwitchArbInt(i64, maxInt(i64)) == 2);57 };
58 try expect(testSwitchArbInt(i64, -1000) == 3);58 }
5959
60 try expect(testSwitchArbInt(u128, 0) == 0);60 fn doTheTest() !void {
61 try expect(testSwitchArbInt(u128, 12) == 1);61 try expect(testSwitchArbInt(u64, 0) == 0);
62 try expect(testSwitchArbInt(u128, maxInt(u128)) == 2);62 try expect(testSwitchArbInt(u64, 12) == 1);
63 try expect(testSwitchArbInt(u128, 5555) == 3);63 try expect(testSwitchArbInt(u64, maxInt(u64)) == 2);
64 try expect(testSwitchArbInt(u64, 5555) == 3);
65
66 try expect(testSwitchArbInt(i64, minInt(i64)) == 0);
67 try expect(testSwitchArbInt(i64, 12) == 1);
68 try expect(testSwitchArbInt(i64, maxInt(i64)) == 2);
69 try expect(testSwitchArbInt(i64, -1000) == 3);
70
71 try expect(testSwitchArbInt(u128, 0) == 0);
72 try expect(testSwitchArbInt(u128, 12) == 1);
73 try expect(testSwitchArbInt(u128, maxInt(u128)) == 2);
74 try expect(testSwitchArbInt(u128, 5555) == 3);
75
76 try expect(testSwitchArbInt(i128, minInt(i128)) == 0);
77 try expect(testSwitchArbInt(i128, 12) == 1);
78 try expect(testSwitchArbInt(i128, maxInt(i128)) == 2);
79 try expect(testSwitchArbInt(i128, -1000) == 3);
80 }
81 };
6482
65 try expect(testSwitchArbInt(i128, minInt(i128)) == 0);83 try S.doTheTest();
66 try expect(testSwitchArbInt(i128, 12) == 1);84 try comptime S.doTheTest();
67 try expect(testSwitchArbInt(i128, maxInt(i128)) == 2);
68 try expect(testSwitchArbInt(i128, -1000) == 3);
69}85}
7086
71fn testSwitchArbInt(comptime T: type, x: T) u32 {87test "dense switch" {
72 return switch (x) {88 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
73 minInt(T) => 0,89 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
74 10...15 => 1,90 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
75 maxInt(T) => 2,91 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
76 else => 3,92 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
93
94 const S = struct {
95 fn unsigned(comptime T: type, x: T) u8 {
96 return switch (x) {
97 0 => 0,
98 1 => 1,
99 2 => 2,
100 3 => 3,
101 else => 4,
102 };
103 }
104
105 fn signed(comptime T: type, x: T) u8 {
106 return switch (x) {
107 -2 => 0,
108 -1 => 1,
109 0 => 2,
110 1 => 3,
111 else => 4,
112 };
113 }
114
115 fn doTheTest() !void {
116 try expect(unsigned(u32, 0) == 0);
117 try expect(unsigned(u32, 1) == 1);
118 try expect(unsigned(u32, 2) == 2);
119 try expect(unsigned(u32, 3) == 3);
120 try expect(unsigned(u32, maxInt(u32)) == 4);
121 try expect(unsigned(u32, (1 << 16) + 1) == 4);
122
123 try expect(signed(i32, -2) == 0);
124 try expect(signed(i32, -1) == 1);
125 try expect(signed(i32, 0) == 2);
126 try expect(signed(i32, 1) == 3);
127 try expect(signed(i32, minInt(i32)) == 4);
128 try expect(signed(i32, -(1 << 16) - 2) == 4);
129 try expect(signed(i32, (1 << 16) + 1) == 4);
130
131 try expect(unsigned(u64, 0) == 0);
132 try expect(unsigned(u64, 1) == 1);
133 try expect(unsigned(u64, 2) == 2);
134 try expect(unsigned(u64, 3) == 3);
135 try expect(unsigned(u64, maxInt(u64)) == 4);
136 try expect(unsigned(u64, (1 << 32) + 1) == 4);
137
138 try expect(signed(i64, -2) == 0);
139 try expect(signed(i64, -1) == 1);
140 try expect(signed(i64, 0) == 2);
141 try expect(signed(i64, 1) == 3);
142 try expect(signed(i64, minInt(i64)) == 4);
143 try expect(signed(i64, -(1 << 32) - 2) == 4);
144 try expect(signed(i64, (1 << 32) + 1) == 4);
145
146 try expect(unsigned(u128, 0) == 0);
147 try expect(unsigned(u128, 1) == 1);
148 try expect(unsigned(u128, 2) == 2);
149 try expect(unsigned(u128, 3) == 3);
150 try expect(unsigned(u128, maxInt(u128)) == 4);
151 try expect(unsigned(u128, (1 << 64) + 1) == 4);
152
153 try expect(signed(i128, -2) == 0);
154 try expect(signed(i128, -1) == 1);
155 try expect(signed(i128, 0) == 2);
156 try expect(signed(i128, 1) == 3);
157 try expect(signed(i128, minInt(i128)) == 4);
158 try expect(signed(i128, -(1 << 64) - 2) == 4);
159 try expect(signed(i128, (1 << 64) + 1) == 4);
160
161 try expect(unsigned(u999, 0) == 0);
162 try expect(unsigned(u999, 1) == 1);
163 try expect(unsigned(u999, 2) == 2);
164 try expect(unsigned(u999, 3) == 3);
165 try expect(unsigned(u999, maxInt(u999)) == 4);
166 try expect(unsigned(u999, (1 << 499) + 1) == 4);
167
168 try expect(signed(i999, -2) == 0);
169 try expect(signed(i999, -1) == 1);
170 try expect(signed(i999, 0) == 2);
171 try expect(signed(i999, 1) == 3);
172 try expect(signed(i999, minInt(i999)) == 4);
173 try expect(signed(i999, -(1 << 499) - 2) == 4);
174 try expect(signed(i999, (1 << 499) + 1) == 4);
175 }
77 };176 };
177
178 try S.doTheTest();
179 try comptime S.doTheTest();
78}180}
79181
80test "implicit comptime switch" {182test "implicit comptime switch" {
test/tests.zig+21
...@@ -1601,6 +1601,27 @@ const module_test_targets = blk: {...@@ -1601,6 +1601,27 @@ const module_test_targets = blk: {
1601 .{1601 .{
1602 .target = .{1602 .target = .{
1603 .cpu_arch = .wasm32,1603 .cpu_arch = .wasm32,
1604 .cpu_model = .{ .explicit = &std.Target.wasm.cpu.mvp },
1605 .os_tag = .wasi,
1606 .abi = .none,
1607 },
1608 .use_llvm = false,
1609 .use_lld = false,
1610 },
1611 .{
1612 .target = .{
1613 .cpu_arch = .wasm32,
1614 .cpu_model = .{ .explicit = &std.Target.wasm.cpu.lime1 },
1615 .os_tag = .wasi,
1616 .abi = .none,
1617 },
1618 .use_llvm = false,
1619 .use_lld = false,
1620 },
1621 .{
1622 .target = .{
1623 .cpu_arch = .wasm32,
1624 .cpu_model = .{ .explicit = &std.Target.wasm.cpu.wasm_v3_0 },
1604 .os_tag = .wasi,1625 .os_tag = .wasi,
1605 .abi = .none,1626 .abi = .none,
1606 },1627 },