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 {
25652565 .cpu = .{
25662566 .arch = cpu_arch,
25672567 .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,
25692569 },
25702570 .os = .{
25712571 .tag = os_tag,
lib/std/atomic.zig+2
......@@ -160,6 +160,8 @@ test Value {
160160}
161161
162162test "Value.swap" {
163 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
164
163165 var x = Value(usize).init(5);
164166 try testing.expectEqual(@as(usize, 5), x.swap(10, .seq_cst));
165167 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) {
514514 i64_atomic_rmw32_add_u = 0x24,
515515 i32_atomic_rmw_sub = 0x25,
516516 i64_atomic_rmw_sub = 0x26,
517 i32_atomic_rmw8_sub_u = 0x27A,
518 i32_atomic_rmw16_sub_u = 0x28A,
519 i64_atomic_rmw8_sub_u = 0x29A,
517 i32_atomic_rmw8_sub_u = 0x27,
518 i32_atomic_rmw16_sub_u = 0x28,
519 i64_atomic_rmw8_sub_u = 0x29,
520520 i64_atomic_rmw16_sub_u = 0x2A,
521521 i64_atomic_rmw32_sub_u = 0x2B,
522522 i32_atomic_rmw_and = 0x2C,
src/codegen/wasm/CodeGen.zig+216-167
......@@ -157,7 +157,7 @@ simd_immediates: std.ArrayList([16]u8) = .empty,
157157/// The Target we're emitting (used to call intInfo)
158158target: *const std.Target,
159159ptr_size: enum { wasm32, wasm64 },
160pt: Zcu.PerThread,
160zcu: *Zcu,
161161/// List of MIR Instructions
162162mir_instructions: std.MultiArrayList(Mir.Inst),
163163/// Contains extra data for MIR
......@@ -380,7 +380,7 @@ pub fn deinit(cg: *CodeGen) void {
380380}
381381
382382pub fn fail(cg: *CodeGen, comptime fmt: []const u8, args: anytype) Error {
383 const zcu = cg.pt.zcu;
383 const zcu = cg.zcu;
384384 const func = zcu.funcInfo(cg.func_index);
385385 return zcu.codegenFail(func.owner_nav, fmt, args);
386386}
......@@ -395,8 +395,7 @@ fn resolveInst(cg: *CodeGen, ref: Air.Inst.Ref) InnerError!WValue {
395395 const gop = try cg.values.getOrPut(cg.gpa, ref);
396396 assert(!gop.found_existing);
397397
398 const pt = cg.pt;
399 const zcu = pt.zcu;
398 const zcu = cg.zcu;
400399 const val: Value = .fromInterned(ref.toInterned().?);
401400 const ty = cg.typeOf(ref);
402401 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 {
420419}
421420
422421fn resolveValue(cg: *CodeGen, val: Value) InnerError!WValue {
423 const zcu = cg.pt.zcu;
422 const zcu = cg.zcu;
424423 const ty = val.typeOf(zcu);
425424
426425 return if (isByRef(ty, zcu, cg.target))
......@@ -761,7 +760,7 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void {
761760 .float32 => |val| try cg.addFloat32(val),
762761 .float64 => |val| try cg.addFloat64(val),
763762 .nav_ref => |nav_ref| {
764 const zcu = cg.pt.zcu;
763 const zcu = cg.zcu;
765764 const ip = &zcu.intern_pool;
766765 if (ip.zigTypeTag(ip.getNav(nav_ref.nav_index).resolved.?.type) == .@"fn") {
767766 assert(nav_ref.offset == 0);
......@@ -782,7 +781,7 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void {
782781 }
783782 },
784783 .uav_ref => |uav| {
785 const zcu = cg.pt.zcu;
784 const zcu = cg.zcu;
786785 const ip = &zcu.intern_pool;
787786 assert(!ip.isFunctionType(ip.typeOf(uav.ip_index)));
788787 const gop = try cg.mir_uavs.getOrPut(cg.gpa, uav.ip_index);
......@@ -853,7 +852,7 @@ fn releaseLocal(cg: *CodeGen, index: u32) void {
853852/// Creates one locals for a given `Type`.
854853/// Returns a corresponding `Wvalue` with `local` as active tag
855854fn allocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {
856 const zcu = cg.pt.zcu;
855 const zcu = cg.zcu;
857856 const valtype = typeToValtype(ty, zcu, cg.target);
858857 const free_list = cg.local_pool.freeList(valtype);
859858 if (free_list.unwrap()) |index| {
......@@ -870,7 +869,7 @@ fn allocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {
870869/// Ensures a new local will be created. This is useful when it's useful
871870/// to use a zero-initialized local.
872871fn ensureAllocLocal(cg: *CodeGen, ty: Type) InnerError!WValue {
873 const zcu = cg.pt.zcu;
872 const zcu = cg.zcu;
874873 try cg.mir_locals.ensureUnusedCapacity(cg.gpa, 1);
875874 try cg.local_pool.locals.ensureUnusedCapacity(cg.gpa, 1);
876875 assert(cg.mir_locals.items.len == cg.local_pool.locals.items.len);
......@@ -905,7 +904,7 @@ pub fn generate(
905904
906905 var code_gen: CodeGen = .{
907906 .gpa = gpa,
908 .pt = pt,
907 .zcu = zcu,
909908 .air = air.*,
910909 .liveness = liveness.*.?,
911910 .owner_nav = cg.owner_nav,
......@@ -940,7 +939,7 @@ pub fn generate(
940939}
941940
942941fn generateInner(cg: *CodeGen, any_returns: bool) InnerError!Mir {
943 const zcu = cg.pt.zcu;
942 const zcu = cg.zcu;
944943 cg.wasm_param_count = @intCast(cg.args.len + @intFromBool(cg.return_value != .none) + @intFromBool(cg.varargs != .none));
945944 cg.initial_stack_value = try cg.ensureAllocLocal(Type.usize);
946945 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
10991098 return cg.emitWValue(value);
11001099 }
11011100
1102 const zcu = cg.pt.zcu;
1101 const zcu = cg.zcu;
11031102
11041103 switch (abi.classifyType(ty, zcu, cg.target)) {
11051104 .direct => |scalar_ty| {
......@@ -1148,8 +1147,7 @@ fn restoreStackPointer(cg: *CodeGen) !void {
11481147///
11491148/// Asserts Type has codegenbits
11501149fn allocStack(cg: *CodeGen, ty: Type) !WValue {
1151 const pt = cg.pt;
1152 const zcu = pt.zcu;
1150 const zcu = cg.zcu;
11531151 assert(ty.hasRuntimeBits(zcu));
11541152
11551153 const abi_size = std.math.cast(u32, ty.abiSize(zcu)) orelse {
......@@ -1187,8 +1185,7 @@ fn allocStackBytes(cg: *CodeGen, size: u32, alignment: Alignment) !WValue {
11871185/// This is different from allocStack where this will use the pointer's alignment
11881186/// if it is set, to ensure the stack alignment will be set correctly.
11891187fn allocStackPtr(cg: *CodeGen, inst: Air.Inst.Index) !WValue {
1190 const pt = cg.pt;
1191 const zcu = pt.zcu;
1188 const zcu = cg.zcu;
11921189 const ptr_ty = cg.typeOfIndex(inst);
11931190 const pointee_ty = ptr_ty.childType(zcu);
11941191
......@@ -1338,15 +1335,25 @@ const SimdStoreStrategy = enum {
13381335/// it using a instruction, rather than an unrolled version.
13391336pub fn determineSimdStoreStrategy(ty: Type, zcu: *const Zcu, target: *const std.Target) SimdStoreStrategy {
13401337 assert(ty.zigTypeTag(zcu) == .vector);
1341 if (ty.bitSize(zcu) != 128) return .unrolled;
1342 if (target.cpu.has(.wasm, .relaxed_simd) or target.cpu.has(.wasm, .simd128)) {
1343 return .direct;
1344 }
1345 return .unrolled;
1338 if (!target.cpu.has(.wasm, .simd128)) return .unrolled;
1339 return switch (ty.toIntern()) {
1340 .vector_16_i8_type,
1341 .vector_16_u8_type,
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 };
13461353}
13471354
13481355fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1349 const zcu = cg.pt.zcu;
1356 const zcu = cg.zcu;
13501357 const air_tags = cg.air.instructions.items(.tag);
13511358 return switch (air_tags[@backingInt(inst)]) {
13521359 // No soft float legalizations are enabled.
......@@ -1482,7 +1489,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
14821489 const rhs = try cg.resolveInst(bin_op.rhs);
14831490 const ty = cg.typeOfIndex(inst);
14841491
1485 if (ty.zigTypeTag(cg.pt.zcu) == .vector) {
1492 if (ty.zigTypeTag(cg.zcu) == .vector) {
14861493 return cg.fail("TODO: implement AIR op: mul_add for vectors", .{});
14871494 }
14881495
......@@ -1500,7 +1507,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
15001507 const rhs = try cg.resolveInst(bin_op.rhs);
15011508 const ty = cg.typeOfIndex(inst);
15021509
1503 if (ty.zigTypeTag(cg.pt.zcu) == .vector) {
1510 if (ty.zigTypeTag(cg.zcu) == .vector) {
15041511 return cg.fail("TODO: implement AIR op: {s} for vectors", .{@tagName(tag)});
15051512 }
15061513
......@@ -1545,7 +1552,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
15451552 defer res_tmp.free(cg);
15461553
15471554 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
15501557 try cg.store(result, res_tmp, ty, .{});
15511558 try cg.store(result, ov_tmp, .u1, .{ .offset = offset });
......@@ -1665,7 +1672,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
16651672 const src_ty = cg.typeOf(ty_op.operand);
16661673 const dest_ty = cg.typeOfIndex(inst);
16671674
1668 if (dest_ty.zigTypeTag(cg.pt.zcu) == .vector) {
1675 if (dest_ty.zigTypeTag(cg.zcu) == .vector) {
16691676 return cg.fail("TODO: implement AIR op: {s} for vectors", .{@tagName(tag)});
16701677 }
16711678
......@@ -1949,7 +1956,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
19491956}
19501957
19511958fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
1952 const zcu = cg.pt.zcu;
1959 const zcu = cg.zcu;
19531960 const ip = &zcu.intern_pool;
19541961
19551962 for (body) |inst| {
......@@ -1969,7 +1976,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
19691976}
19701977
19711978fn airRet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1972 const zcu = cg.pt.zcu;
1979 const zcu = cg.zcu;
19731980 const un_op = cg.air.instructions.items(.data)[@backingInt(inst)].un_op;
19741981 const operand = try cg.resolveInst(un_op);
19751982 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 {
20092016}
20102017
20112018fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2012 const zcu = cg.pt.zcu;
2019 const zcu = cg.zcu;
20132020 const child_type = cg.typeOfIndex(inst).childType(zcu);
20142021
20152022 const result = result: {
......@@ -2029,7 +2036,7 @@ fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
20292036}
20302037
20312038fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2032 const zcu = cg.pt.zcu;
2039 const zcu = cg.zcu;
20332040 const un_op = cg.air.instructions.items(.data)[@backingInt(inst)].un_op;
20342041 const operand = try cg.resolveInst(un_op);
20352042 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)
20662073 const args = call.args;
20672074 const ty = cg.typeOf(call.callee);
20682075
2069 const pt = cg.pt;
2070 const zcu = pt.zcu;
2076 const zcu = cg.zcu;
20712077 const ip = &zcu.intern_pool;
20722078 const fn_ty = switch (ty.zigTypeTag(zcu)) {
20732079 .@"fn" => ty,
......@@ -2240,7 +2246,7 @@ fn airVaCopy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
22402246}
22412247
22422248fn airVaArg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2243 const zcu = cg.pt.zcu;
2249 const zcu = cg.zcu;
22442250 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
22452251 const operand = try cg.resolveInst(ty_op.operand);
22462252
......@@ -2312,8 +2318,7 @@ fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
23122318}
23132319
23142320fn airStore(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {
2315 const pt = cg.pt;
2316 const zcu = pt.zcu;
2321 const zcu = cg.zcu;
23172322 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;
23182323
23192324 const lhs = try cg.resolveInst(bin_op.lhs);
......@@ -2356,8 +2361,7 @@ const MemArg = struct {
23562361
23572362fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, memarg: MemArg) InnerError!void {
23582363 assert(!(lhs != .stack and rhs == .stack));
2359 const pt = cg.pt;
2360 const zcu = pt.zcu;
2364 const zcu = cg.zcu;
23612365 const abi_size = ty.abiSize(zcu);
23622366
23632367 if (!ty.hasRuntimeBits(zcu)) return;
......@@ -2422,8 +2426,7 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, memarg: MemArg) Inner
24222426}
24232427
24242428fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2425 const pt = cg.pt;
2426 const zcu = pt.zcu;
2429 const zcu = cg.zcu;
24272430 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
24282431 const operand = try cg.resolveInst(ty_op.operand);
24292432 const elem_ty = ty_op.ty;
......@@ -2449,7 +2452,7 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
24492452/// Loads an operand from the linear memory section.
24502453/// NOTE: Leaves the value on the stack, if isByRef == false.
24512454fn load(cg: *CodeGen, operand: WValue, ty: Type, memarg: MemArg) InnerError!WValue {
2452 const zcu = cg.pt.zcu;
2455 const zcu = cg.zcu;
24532456
24542457 const natural_alignment = ty.abiAlignment(zcu);
24552458 // wasm memory instruction alignment is <= access width
......@@ -2527,8 +2530,7 @@ fn load(cg: *CodeGen, operand: WValue, ty: Type, memarg: MemArg) InnerError!WVal
25272530}
25282531
25292532fn airArg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2530 const pt = cg.pt;
2531 const zcu = pt.zcu;
2533 const zcu = cg.zcu;
25322534 const arg_index = cg.arg_index;
25332535 const arg = cg.args[arg_index];
25342536 const cc = zcu.typeToFunc(zcu.navValue(cg.owner_nav).typeOf(zcu)).?.cc;
......@@ -2580,7 +2582,7 @@ const IntType = struct {
25802582 // Adapted from x86_64 backend
25812583 // Differ from Type.intInfo as it treats pointers/booleans/packed/enums/errors as integer
25822584 fn fromType(cg: *CodeGen, ty: Type) IntType {
2583 const zcu = cg.pt.zcu;
2585 const zcu = cg.zcu;
25842586 const ip = &zcu.intern_pool;
25852587 var ty_index = ty.ip_index;
25862588 while (true) switch (ip.indexToKey(ty_index)) {
......@@ -2589,17 +2591,11 @@ const IntType = struct {
25892591 .one, .many, .c => .{ .is_signed = false, .bits = cg.target.ptrBitWidth() },
25902592 .slice => unreachable,
25912593 },
2592 .opt_type => |opt_child| return if (!Type.fromInterned(opt_child).hasRuntimeBits(zcu))
2593 .{ .is_signed = false, .bits = 1 }
2594 else switch (ip.indexToKey(opt_child)) {
2595 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
2596 .one, .many => switch (ptr_type.flags.is_allowzero) {
2597 false => .{ .is_signed = false, .bits = cg.target.ptrBitWidth() },
2598 true => unreachable,
2599 },
2600 .slice, .c => unreachable,
2601 },
2602 else => unreachable,
2594 .opt_type => |opt_child| {
2595 if (!Type.fromInterned(opt_child).hasRuntimeBits(zcu))
2596 return .{ .is_signed = false, .bits = 1 };
2597 assert(Type.fromInterned(ty_index).optionalReprIsPayload(zcu));
2598 ty_index = opt_child;
26032599 },
26042600 .error_union_type => |error_union_type| return if (!Type.fromInterned(error_union_type.payload_type)
26052601 .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
50375033}
50385034
50395035fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerError!WValue {
5040 const pt = cg.pt;
5041 const zcu = pt.zcu;
5036 const zcu = cg.zcu;
50425037 const ip = &zcu.intern_pool;
50435038 const ptr = zcu.intern_pool.indexToKey(ptr_val).ptr;
50445039 const offset: u64 = prev_offset + ptr.byte_offset;
......@@ -5052,7 +5047,10 @@ fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerErro
50525047 .{ .uav_ref = .{ .ip_index = uav.val, .offset = @intCast(offset), .orig_ptr_ty = uav.orig_ty } }
50535048 else
50545049 .{ .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 },
50565054 .eu_payload => |eu_ptr| try cg.lowerPtr(
50575055 eu_ptr,
50585056 offset + codegen.errUnionPayloadOffset(
......@@ -5091,8 +5089,7 @@ fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerErro
50915089
50925090/// Asserts that `isByRef` returns `false` for `val.typeOf(zcu)`.
50935091fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue {
5094 const pt = cg.pt;
5095 const zcu = pt.zcu;
5092 const zcu = cg.zcu;
50965093 const ty = val.typeOf(zcu);
50975094 assert(!isByRef(ty, zcu, cg.target));
50985095 const ip = &zcu.intern_pool;
......@@ -5150,22 +5147,16 @@ fn lowerConstant(cg: *CodeGen, val: Value) InnerError!WValue {
51505147 }
51515148 },
51525149 .err => |err| {
5153 const int = try pt.getErrorValue(err.name);
5150 const int = ip.getErrorValueIfExists(err.name).?;
51545151 return .{ .imm32 = int };
51555152 },
51565153 .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 };
51655154 const payload_type = ty.errorUnionPayload(zcu);
51665155 if (!payload_type.hasRuntimeBits(zcu)) {
5167 // We use the error type directly as the type.
5168 return cg.lowerConstant(err_val);
5156 return .{ .imm32 = switch (error_union.val) {
5157 .err_name => |err_name| ip.getErrorValueIfExists(err_name).?,
5158 .payload => 0,
5159 } };
51695160 }
51705161
51715162 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 {
51885179 } else {
51895180 return .{ .imm32 = @intFromBool(!val.isNull(zcu)) };
51905181 },
5191 .aggregate => switch (ip.indexToKey(ty.ip_index)) {
5192 .array_type => return cg.fail("Wasm TODO: LowerConstant for {f}", .{ty.fmt(zcu)}),
5193 .vector_type => {
5182 .aggregate => |aggregate| switch (ip.indexToKey(ty.ip_index)) {
5183 .array_type => unreachable,
5184 .vector_type => |vector_type| {
51945185 assert(determineSimdStoreStrategy(ty, zcu, cg.target) == .direct);
51955186 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 }
51975203 return cg.storeSimdImmd(buf);
51985204 },
51995205 .struct_type => unreachable, // packed structs use `bitpack`
......@@ -5214,8 +5220,9 @@ fn storeSimdImmd(cg: *CodeGen, value: [16]u8) !WValue {
52145220}
52155221
52165222fn emitUndefined(cg: *CodeGen, ty: Type) InnerError!WValue {
5217 const zcu = cg.pt.zcu;
5223 const zcu = cg.zcu;
52185224 switch (ty.zigTypeTag(zcu)) {
5225 .vector => return cg.storeSimdImmd(@splat(0xaa)),
52195226 .bool, .error_set => return .{ .imm32 = 0xaaaaaaaa },
52205227 .int, .@"enum" => switch (ty.intInfo(zcu).bits) {
52215228 0...32 => return .{ .imm32 = 0xaaaaaaaa },
......@@ -5256,7 +5263,7 @@ fn airBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
52565263}
52575264
52585265fn 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
52615268 if (block_ty.isNoReturn(zcu)) {
52625269 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
53655372 const lhs = try cg.resolveInst(bin_op.lhs);
53665373 const rhs = try cg.resolveInst(bin_op.rhs);
53675374 const operand_ty = cg.typeOf(bin_op.lhs);
5368 const zcu = cg.pt.zcu;
5375 const zcu = cg.zcu;
53695376
53705377 const type_tag = operand_ty.zigTypeTag(zcu);
53715378
......@@ -5597,10 +5604,10 @@ fn airCmpLteErrorsLen(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
55975604 const operand = try cg.resolveInst(un_op);
55985605
55995606 try cg.emitWValue(operand);
5600 const pt = cg.pt;
5601 const err_int_ty = try pt.errorIntType();
5607 const zcu = cg.zcu;
5608 const err_int_ty: IntType = .{ .is_signed = false, .bits = zcu.errorSetBits() };
56025609 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
56055612 return cg.finishAir(inst, result, &.{un_op});
56065613}
......@@ -5656,7 +5663,7 @@ fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
56565663}
56575664
56585665fn airNopCast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5659 const zcu = cg.pt.zcu;
5666 const zcu = cg.zcu;
56605667 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
56615668
56625669 const operand_ty = cg.typeOf(ty_op.operand);
......@@ -5670,7 +5677,7 @@ fn airNopCast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
56705677}
56715678
56725679fn airIntFromPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5673 const zcu = cg.pt.zcu;
5680 const zcu = cg.zcu;
56745681 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
56755682
56765683 const operand_ty = cg.typeOf(ty_op.operand);
......@@ -5689,7 +5696,7 @@ fn airIntFromPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
56895696}
56905697
56915698fn airUnionFromEnum(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5692 const zcu = cg.pt.zcu;
5699 const zcu = cg.zcu;
56935700 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
56945701
56955702 const union_ty = cg.typeOfIndex(inst);
......@@ -5721,7 +5728,7 @@ const BitcastClass = union(enum) {
57215728};
57225729
57235730fn bitcastClass(cg: *CodeGen, ty: Type) BitcastClass {
5724 const zcu = cg.pt.zcu;
5731 const zcu = cg.zcu;
57255732 return switch (ty.zigTypeTag(zcu)) {
57265733 .bool,
57275734 .int,
......@@ -5739,7 +5746,7 @@ fn bitcastClass(cg: *CodeGen, ty: Type) BitcastClass {
57395746fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerError!WValue {
57405747 if (dest_ty.eql(src_ty)) return operand;
57415748
5742 const zcu = cg.pt.zcu;
5749 const zcu = cg.zcu;
57435750 const src_class = cg.bitcastClass(src_ty);
57445751 const dest_class = cg.bitcastClass(dest_ty);
57455752 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
57855792 .f80, .f128 => unreachable,
57865793 },
57875794 .int => {},
5788 .aggregate => unreachable,
5795 .aggregate => return operand, // both v128
57895796 }
57905797
57915798 switch (dest_class) {
......@@ -5815,7 +5822,7 @@ fn bitcast(cg: *CodeGen, dest_ty: Type, src_ty: Type, operand: WValue) InnerErro
58155822}
58165823
58175824fn airStructFieldPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5818 const zcu = cg.pt.zcu;
5825 const zcu = cg.zcu;
58195826 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
58205827 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 {
58275834}
58285835
58295836fn airStructFieldPtrIndex(cg: *CodeGen, inst: Air.Inst.Index, index: u32) InnerError!void {
5830 const zcu = cg.pt.zcu;
5837 const zcu = cg.zcu;
58315838 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
58325839 const struct_ptr = try cg.resolveInst(ty_op.operand);
58335840 const struct_ptr_ty = cg.typeOf(ty_op.operand);
......@@ -5845,8 +5852,7 @@ fn structFieldPtr(
58455852 struct_ty: Type,
58465853 index: u32,
58475854) InnerError!WValue {
5848 const pt = cg.pt;
5849 const zcu = pt.zcu;
5855 const zcu = cg.zcu;
58505856 const result_ty = cg.typeOfIndex(inst);
58515857 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(zcu);
58525858
......@@ -5868,8 +5874,7 @@ fn structFieldPtr(
58685874}
58695875
58705876fn airAggFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
5871 const pt = cg.pt;
5872 const zcu = pt.zcu;
5877 const zcu = cg.zcu;
58735878 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
58745879 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 {
58975902
58985903// Both `.switch_br` and `.loop_switch_br` are noreturn.
58995904fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) InnerError!void {
5900 const pt = cg.pt;
5901 const zcu = pt.zcu;
5905 const zcu = cg.zcu;
59025906
59035907 const switch_br = cg.air.unwrapSwitch(inst);
59045908 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
60136017 if (use_br_table) {
60146018 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
60166027 const br_value_original = try cg.intSub(int_ty, target, try cg.resolveValue(min.?));
60176028 _ = try cg.intCast(.u32, int_ty, br_value_original);
60186029
......@@ -6119,7 +6130,7 @@ fn airSwitchDispatch(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
61196130}
61206131
61216132fn 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;
61236134 const un_op = cg.air.instructions.items(.data)[@backingInt(inst)].un_op;
61246135 const operand = try cg.resolveInst(un_op);
61256136 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
61586169/// E!T -> T op_is_ptr == false
61596170/// *(E!T) -> *T op_is_prt == true
61606171fn airUnwrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {
6161 const zcu = cg.pt.zcu;
6172 const zcu = cg.zcu;
61626173 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
61636174
61646175 const operand = try cg.resolveInst(ty_op.operand);
......@@ -6190,7 +6201,7 @@ fn airUnwrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool)
61906201/// *(E!T) -> E op_is_ptr == true
61916202/// NOTE: op_is_ptr will not change return type
61926203fn airUnwrapErrUnionError(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {
6193 const zcu = cg.pt.zcu;
6204 const zcu = cg.zcu;
61946205 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
61956206
61966207 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
62156226}
62166227
62176228fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6218 const zcu = cg.pt.zcu;
6229 const zcu = cg.zcu;
62196230 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
62206231
62216232 const operand = try cg.resolveInst(ty_op.operand);
......@@ -6244,7 +6255,7 @@ fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
62446255}
62456256
62466257fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6247 const zcu = cg.pt.zcu;
6258 const zcu = cg.zcu;
62486259 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
62496260
62506261 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
62846295/// For a given type and operand, checks if it's considered `null`.
62856296/// NOTE: Leaves the result on the stack
62866297fn isNull(cg: *CodeGen, operand: WValue, op_ty: Type, opcode: std.wasm.Opcode, op_kind: OpKind) InnerError!WValue {
6287 const pt = cg.pt;
6288 const zcu = pt.zcu;
6298 const zcu = cg.zcu;
62896299 const optional_ty = switch (op_kind) {
62906300 .value => op_ty,
62916301 .ptr => op_ty.childType(zcu),
......@@ -6330,7 +6340,7 @@ fn isNull(cg: *CodeGen, operand: WValue, op_ty: Type, opcode: std.wasm.Opcode, o
63306340}
63316341
63326342fn airOptionalPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6333 const zcu = cg.pt.zcu;
6343 const zcu = cg.zcu;
63346344 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
63356345 const opt_ty = cg.typeOf(ty_op.operand);
63366346 const payload_ty = cg.typeOfIndex(inst);
......@@ -6352,7 +6362,7 @@ fn airOptionalPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
63526362}
63536363
63546364fn airOptionalPayloadPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6355 const zcu = cg.pt.zcu;
6365 const zcu = cg.zcu;
63566366 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
63576367 const operand = try cg.resolveInst(ty_op.operand);
63586368 const opt_ty = cg.typeOf(ty_op.operand).childType(zcu);
......@@ -6369,8 +6379,7 @@ fn airOptionalPayloadPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
63696379}
63706380
63716381fn airOptionalPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6372 const pt = cg.pt;
6373 const zcu = pt.zcu;
6382 const zcu = cg.zcu;
63746383 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
63756384 const operand = try cg.resolveInst(ty_op.operand);
63766385 const opt_ty = cg.typeOf(ty_op.operand).childType(zcu);
......@@ -6394,8 +6403,7 @@ fn airOptionalPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void
63946403fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
63956404 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
63966405 const payload_ty = cg.typeOf(ty_op.operand);
6397 const pt = cg.pt;
6398 const zcu = pt.zcu;
6406 const zcu = cg.zcu;
63996407
64006408 const result = result: {
64016409 if (!payload_ty.hasRuntimeBits(zcu)) {
......@@ -6451,7 +6459,7 @@ fn airSliceLen(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
64516459}
64526460
64536461fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6454 const zcu = cg.pt.zcu;
6462 const zcu = cg.zcu;
64556463 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;
64566464
64576465 const slice_ty = cg.typeOf(bin_op.lhs);
......@@ -6472,7 +6480,7 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
64726480}
64736481
64746482fn airSliceElemPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6475 const zcu = cg.pt.zcu;
6483 const zcu = cg.zcu;
64766484 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
64776485 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 {
65076515}
65086516
65096517fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6510 const zcu = cg.pt.zcu;
6518 const zcu = cg.zcu;
65116519 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
65126520
65136521 const operand = try cg.resolveInst(ty_op.operand);
......@@ -6527,7 +6535,7 @@ fn airArrayToSlice(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
65276535}
65286536
65296537fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6530 const zcu = cg.pt.zcu;
6538 const zcu = cg.zcu;
65316539 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;
65326540
65336541 const ptr_ty = cg.typeOf(bin_op.lhs);
......@@ -6552,7 +6560,7 @@ fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
65526560}
65536561
65546562fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6555 const zcu = cg.pt.zcu;
6563 const zcu = cg.zcu;
65566564 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
65576565 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 {
65776585}
65786586
65796587fn airPtrBinOp(cg: *CodeGen, inst: Air.Inst.Index, op: PointerOffsetOp) InnerError!void {
6580 const zcu = cg.pt.zcu;
6588 const zcu = cg.zcu;
65816589 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
65826590 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
65966604}
65976605
65986606fn airMemset(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {
6599 const zcu = cg.pt.zcu;
6607 const zcu = cg.zcu;
66006608 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;
66016609
66026610 const ptr = try cg.resolveInst(bin_op.lhs);
......@@ -6630,7 +6638,7 @@ fn airMemset(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void {
66306638/// this to wasm's memset instruction. When the feature is not present,
66316639/// we implement it manually.
66326640fn 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;
66346642 const abi_size = @as(u32, @intCast(elem_ty.abiSize(zcu)));
66356643 const len_known_neq_0 = switch (len) {
66366644 .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)
67506758}
67516759
67526760fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6753 const zcu = cg.pt.zcu;
6761 const zcu = cg.zcu;
67546762 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;
67556763
67566764 const array_ty = cg.typeOf(bin_op.lhs);
......@@ -6804,7 +6812,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
68046812}
68056813
68066814fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6807 const zcu = cg.pt.zcu;
6815 const zcu = cg.zcu;
68086816 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
68096817 const operand = try cg.resolveInst(ty_op.operand);
68106818 const ty = cg.typeOfIndex(inst);
......@@ -6875,8 +6883,7 @@ fn airSelect(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
68756883}
68766884
68776885fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6878 const pt = cg.pt;
6879 const zcu = pt.zcu;
6886 const zcu = cg.zcu;
68806887
68816888 const unwrapped = cg.air.unwrapShuffleOne(zcu, inst);
68826889 const result_ty = unwrapped.result_ty;
......@@ -6907,8 +6914,7 @@ fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
69076914}
69086915
69096916fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6910 const pt = cg.pt;
6911 const zcu = pt.zcu;
6917 const zcu = cg.zcu;
69126918
69136919 const unwrapped = cg.air.unwrapShuffleTwo(zcu, inst);
69146920 const result_ty = unwrapped.result_ty;
......@@ -6984,8 +6990,7 @@ fn airReduce(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
69846990}
69856991
69866992fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
6987 const pt = cg.pt;
6988 const zcu = pt.zcu;
6993 const zcu = cg.zcu;
69896994 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
69906995 const result_ty = cg.typeOfIndex(inst);
69916996 const len = @as(usize, @intCast(result_ty.arrayLen(zcu)));
......@@ -6994,31 +6999,59 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
69946999 const result: WValue = result_value: {
69957000 switch (result_ty.zigTypeTag(zcu)) {
69967001 .array, .vector => {
6997 const result = try cg.allocStack(result_ty);
69987002 const elem_ty = result_ty.childType(zcu);
6999 const elem_size = elem_ty.abiSize(zcu);
7000 const sentinel = result_ty.sentinel(zcu);
7001
7002 var offset: u64 = 0;
7003 for (elements) |elem| {
7004 const elem_val = try cg.resolveInst(elem);
7005 try cg.store(result, elem_val, elem_ty, .{ .offset = offset });
7006 offset += elem_size;
7007 }
7008 if (sentinel) |s| {
7009 const val = try cg.resolveValue(s);
7010 try cg.store(result, val, elem_ty, .{ .offset = offset });
7003 if (isByRef(result_ty, zcu, cg.target)) {
7004 const result = try cg.allocStack(result_ty);
7005 const elem_size = elem_ty.abiSize(zcu);
7006 const sentinel = result_ty.sentinel(zcu);
7007
7008 var offset: u64 = 0;
7009 for (elements) |elem| {
7010 const elem_val = try cg.resolveInst(elem);
7011 try cg.store(result, elem_val, elem_ty, .{ .offset = offset });
7012 offset += elem_size;
7013 }
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;
70117044 }
7012 break :result_value result;
70137045 },
70147046 .@"struct" => switch (result_ty.containerLayout(zcu)) {
70157047 .@"packed" => unreachable, // legalize .expand_packed_aggregate_init
70167048 else => {
70177049 const result = try cg.allocStack(result_ty);
70187050 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
70217053 const elem_ty = result_ty.fieldType(elem_index, zcu);
7054 if (!elem_ty.hasRuntimeBits(zcu)) continue;
70227055 const field_offset = result_ty.structFieldOffset(elem_index, zcu);
70237056
70247057 const value = try cg.resolveInst(elem);
......@@ -7038,8 +7071,7 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
70387071}
70397072
70407073fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7041 const pt = cg.pt;
7042 const zcu = pt.zcu;
7074 const zcu = cg.zcu;
70437075 const ip = &zcu.intern_pool;
70447076 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
70457077 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 {
70517083 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[extra.field_index]);
70527084 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: {
70557087 const tag_ty = union_ty.unionTagTypeHypothetical(zcu);
70567088 const enum_field_index = tag_ty.enumFieldIndex(field_name, zcu).?;
7057 const tag_val = try pt.enumValueFieldIndex(tag_ty, enum_field_index);
7058 break :blk try cg.lowerConstant(tag_val);
7089 const enum_type = ip.loadEnumType(tag_ty.toIntern());
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));
70597107 };
70607108 if (layout.payload_size == 0) {
70617109 if (layout.tag_size == 0) {
......@@ -7116,8 +7164,7 @@ fn airWasmMemoryGrow(cg: *CodeGen, inst: Air.Inst.Index) !void {
71167164}
71177165
71187166fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7119 const pt = cg.pt;
7120 const zcu = pt.zcu;
7167 const zcu = cg.zcu;
71217168 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;
71227169 const un_ty = cg.typeOf(bin_op.lhs).childType(zcu);
71237170 const tag_ty = cg.typeOf(bin_op.rhs);
......@@ -7141,7 +7188,7 @@ fn airSetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
71417188}
71427189
71437190fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7144 const zcu = cg.pt.zcu;
7191 const zcu = cg.zcu;
71457192 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
71467193
71477194 const un_ty = cg.typeOf(ty_op.operand);
......@@ -7161,7 +7208,7 @@ fn airGetUnionTag(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
71617208}
71627209
71637210fn airErrUnionPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7164 const zcu = cg.pt.zcu;
7211 const zcu = cg.zcu;
71657212 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
71667213
71677214 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
71857232}
71867233
71877234fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7188 const pt = cg.pt;
7189 const zcu = pt.zcu;
7235 const zcu = cg.zcu;
71907236 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
71917237 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 {
72257271}
72267272
72277273fn sliceOrArrayPtr(cg: *CodeGen, ptr: WValue, ptr_ty: Type) InnerError!WValue {
7228 const zcu = cg.pt.zcu;
7274 const zcu = cg.zcu;
72297275 if (ptr_ty.isSlice(zcu)) {
72307276 return cg.slicePtr(ptr);
72317277 } else {
......@@ -7234,7 +7280,7 @@ fn sliceOrArrayPtr(cg: *CodeGen, ptr: WValue, ptr_ty: Type) InnerError!WValue {
72347280}
72357281
72367282fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7237 const zcu = cg.pt.zcu;
7283 const zcu = cg.zcu;
72387284 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;
72397285 const dst = try cg.resolveInst(bin_op.lhs);
72407286 const dst_ty = cg.typeOf(bin_op.lhs);
......@@ -7268,7 +7314,7 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
72687314}
72697315
72707316fn airMemmove(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7271 const zcu = cg.pt.zcu;
7317 const zcu = cg.zcu;
72727318 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;
72737319 const dst = try cg.resolveInst(bin_op.lhs);
72747320 const dst_ty = cg.typeOf(bin_op.lhs);
......@@ -7319,9 +7365,9 @@ fn airErrorName(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
73197365 //
73207366 // As the names are global and the slice elements are constant, we do not have
73217367 // to make a copy of the ptr+value but can point towards them directly.
7322 const pt = cg.pt;
7368 const zcu = cg.zcu;
73237369 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
73267372 // Lowers to a i32.const or i64.const with the error table memory address.
73277373 cg.error_name_table_ref_count += 1;
......@@ -7382,7 +7428,7 @@ fn airTry(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
73827428}
73837429
73847430fn airTryPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7385 const zcu = cg.pt.zcu;
7431 const zcu = cg.zcu;
73867432 const unwrapped_try = cg.air.unwrapTryPtr(inst);
73877433 const err_union_ptr = try cg.resolveInst(unwrapped_try.error_union_ptr);
73887434 const body = unwrapped_try.else_body;
......@@ -7405,7 +7451,7 @@ fn lowerTry(
74057451 err_union_ty: Type,
74067452 operand_is_ptr: bool,
74077453) InnerError!WValue {
7408 const zcu = cg.pt.zcu;
7454 const zcu = cg.zcu;
74097455 const branch_liveness = cg.liveness.getCondBr(inst);
74107456
74117457 const pl_ty = err_union_ty.errorUnionPayload(zcu);
......@@ -7465,7 +7511,7 @@ fn callIntrinsic(
74657511 args: []const WValue,
74667512) InnerError!WValue {
74677513 assert(param_types.len == args.len);
7468 const zcu = cg.pt.zcu;
7514 const zcu = cg.zcu;
74697515
74707516 // Always pass over C-ABI
74717517
......@@ -7523,7 +7569,7 @@ fn airIsNamedEnumValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
75237569}
75247570
75257571fn airErrorSetHasValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7526 const zcu = cg.pt.zcu;
7572 const zcu = cg.zcu;
75277573 const ip = &zcu.intern_pool;
75287574 const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op;
75297575
......@@ -7610,7 +7656,7 @@ inline fn useAtomicFeature(cg: *const CodeGen) bool {
76107656}
76117657
76127658fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7613 const zcu = cg.pt.zcu;
7659 const zcu = cg.zcu;
76147660 const ty_pl = cg.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
76157661 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 {
76367682 1 => .i32_atomic_rmw8_cmpxchg_u,
76377683 2 => .i32_atomic_rmw16_cmpxchg_u,
76387684 4 => .i32_atomic_rmw_cmpxchg,
7639 8 => .i32_atomic_rmw_cmpxchg,
7685 8 => .i64_atomic_rmw_cmpxchg,
76407686 else => |size| return cg.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}),
76417687 }, .{
76427688 .offset = ptr_operand.memOffset(),
......@@ -7688,7 +7734,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
76887734}
76897735
76907736fn airAtomicLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7691 const zcu = cg.pt.zcu;
7737 const zcu = cg.zcu;
76927738 const atomic_load = cg.air.instructions.items(.data)[@backingInt(inst)].atomic_load;
76937739 const ptr = try cg.resolveInst(atomic_load.ptr);
76947740 const ty = cg.typeOfIndex(inst);
......@@ -7714,7 +7760,7 @@ fn airAtomicLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
77147760}
77157761
77167762fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7717 const zcu = cg.pt.zcu;
7763 const zcu = cg.zcu;
77187764 const pl_op = cg.air.instructions.items(.data)[@backingInt(inst)].pl_op;
77197765 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 {
77247770 const op: std.lang.AtomicRmwOp = extra.op();
77257771
77267772 if (cg.useAtomicFeature()) {
7773 if (ty.isAnyFloat()) {
7774 return cg.fail("TODO: atomic rmw on floats", .{});
7775 }
77277776 const int_ty: IntType = .fromType(cg, ty);
77287777 switch (op) {
77297778 .Max,
......@@ -7918,7 +7967,7 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
79187967}
79197968
79207969fn airAtomicStore(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7921 const zcu = cg.pt.zcu;
7970 const zcu = cg.zcu;
79227971 const bin_op = cg.air.instructions.items(.data)[@backingInt(inst)].bin_op;
79237972
79247973 const ptr = try cg.resolveInst(bin_op.lhs);
......@@ -7954,7 +8003,7 @@ fn airFrameAddress(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
79548003
79558004fn airRuntimeNavPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
79568005 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.?;
79588007 if (mod.single_threaded) {
79598008 const result: WValue = .{ .nav_ref = .{
79608009 .nav_index = ty_nav.nav,
......@@ -7970,7 +8019,7 @@ fn airAsm(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
79708019 const outputs = unwrapped_asm.outputs;
79718020 const inputs = unwrapped_asm.inputs;
79728021
7973 const zcu = cg.pt.zcu;
8022 const zcu = cg.zcu;
79748023 const output_ty = cg.typeOfIndex(inst);
79758024
79768025 const result: WValue = if (output_ty.hasRuntimeBits(zcu))
......@@ -8037,11 +8086,11 @@ fn airAsm(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
80378086}
80388087
80398088fn typeOf(cg: *CodeGen, inst: Air.Inst.Ref) Type {
8040 const zcu = cg.pt.zcu;
8089 const zcu = cg.zcu;
80418090 return cg.air.typeOf(inst, &zcu.intern_pool);
80428091}
80438092
80448093fn typeOfIndex(cg: *CodeGen, inst: Air.Inst.Index) Type {
8045 const zcu = cg.pt.zcu;
8094 const zcu = cg.zcu;
80468095 return cg.air.typeOfIndex(inst, &zcu.intern_pool);
80478096}
src/codegen/wasm/Emit.zig+2-2
......@@ -27,7 +27,7 @@ pub fn lower(emit: *Emit) Error!void {
2727 const wasm = emit.wasm;
2828 const comp = wasm.base.comp;
2929 const gpa = comp.gpa;
30 const is_obj = comp.config.output_mode == .Obj;
30 const is_obj = wasm.base.isRelocatable();
3131 const target = &comp.root_mod.resolved_target.result;
3232 const is_wasm32 = target.cpu.arch == .wasm32;
3333
......@@ -1028,7 +1028,7 @@ fn navRefOff(wasm: *Wasm, code: *ArrayList(u8), data: Mir.NavRefOff, is_wasm32:
10281028 const zcu = comp.zcu.?;
10291029 const ip = &zcu.intern_pool;
10301030 const gpa = comp.gpa;
1031 const is_obj = comp.config.output_mode == .Obj;
1031 const is_obj = wasm.base.isRelocatable();
10321032 const nav_ty = ip.getNav(data.nav_index).resolved.?.type;
10331033 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 {
181803181803 .one, .many, .c => .{ .signedness = .unsigned, .bits = cg.target.ptrBitWidth() },
181804181804 .slice => null,
181805181805 },
181806 .opt_type => |opt_child| return if (!Type.fromInterned(opt_child).hasRuntimeBits(zcu))
181807 .{ .signedness = .unsigned, .bits = 1 }
181808 else switch (ip.indexToKey(opt_child)) {
181809 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
181810 .one, .many => switch (ptr_type.flags.is_allowzero) {
181811 false => .{ .signedness = .unsigned, .bits = cg.target.ptrBitWidth() },
181812 true => null,
181813 },
181814 .slice, .c => null,
181815 },
181816 else => null,
181806 .opt_type => |opt_child| {
181807 if (!Type.fromInterned(opt_child).hasRuntimeBits(zcu)) {
181808 return .{ .signedness = .unsigned, .bits = 1 };
181809 }
181810 if (Type.fromInterned(ty_index).optionalReprIsPayload(zcu)) {
181811 ty_index = opt_child;
181812 continue;
181813 }
181814 return null;
181817181815 },
181818181816 .error_union_type => |error_union_type| return if (!Type.fromInterned(error_union_type.payload_type)
181819181817 .hasRuntimeBits(zcu)) .{ .signedness = .unsigned, .bits = zcu.errorSetBits() } else null,
src/link/Wasm.zig+48-47
......@@ -79,6 +79,7 @@ growable_table: bool,
7979name: []const u8,
8080/// List of relocatable files to be linked into the final binary.
8181objects: std.ArrayList(Object) = .empty,
82archive_builder: Archive.Builder = .{},
8283
8384func_types: std.array_hash_map.Auto(FunctionType, void) = .empty,
8485/// Provides a mapping of both imports and provided functions to symbol name.
......@@ -467,8 +468,7 @@ pub const OutputDataIndex = enum(u32) {
467468 }
468469
469470 pub fn fromUav(wasm: *const Wasm, ip_index: InternPool.Index) OutputDataIndex {
470 const comp = wasm.base.comp;
471 const resolution: ObjectDataImport.Resolution = if (comp.config.output_mode == .Obj)
471 const resolution: ObjectDataImport.Resolution = if (wasm.base.isRelocatable())
472472 .pack(wasm, .{ .uav_obj = @fromBackingInt(@intCast(wasm.uavs_obj.getIndex(ip_index).?)) })
473473 else
474474 .pack(wasm, .{ .uav_exe = @fromBackingInt(@intCast(wasm.uavs_exe.getIndex(ip_index).?)) });
......@@ -482,7 +482,7 @@ pub const OutputDataIndex = enum(u32) {
482482 if (nav.getExtern(ip) != null) {
483483 return fromSymbolName(wasm, wasm.imports.get(nav_index).?);
484484 }
485 const resolution: ObjectDataImport.Resolution = if (wasm.base.comp.config.output_mode == .Obj)
485 const resolution: ObjectDataImport.Resolution = if (wasm.base.isRelocatable())
486486 .pack(wasm, .{ .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(nav_index).?)) })
487487 else
488488 .pack(wasm, .{ .nav_exe = @fromBackingInt(@intCast(wasm.navs_exe.getIndex(nav_index).?)) });
......@@ -500,7 +500,7 @@ pub const GlobalIndex = enum(u32) {
500500 /// Same as `stack_pointer` but with a safety assertion.
501501 pub fn stackPointer(wasm: *const Wasm) ObjectGlobal.Index {
502502 const comp = wasm.base.comp;
503 assert(comp.config.output_mode != .Obj);
503 assert(!wasm.base.isRelocatable());
504504 assert(comp.zcu != null);
505505 return .stack_pointer;
506506 }
......@@ -879,8 +879,7 @@ const ZcuDataStarts = struct {
879879 uavs_i: u32,
880880
881881 fn init(wasm: *const Wasm) ZcuDataStarts {
882 const comp = wasm.base.comp;
883 const is_obj = comp.config.output_mode == .Obj;
882 const is_obj = wasm.base.isRelocatable();
884883 return if (is_obj) initObj(wasm) else initExe(wasm);
885884 }
886885
......@@ -897,8 +896,7 @@ const ZcuDataStarts = struct {
897896 }
898897
899898 fn finish(zds: ZcuDataStarts, wasm: *Wasm, pt: Zcu.PerThread) !void {
900 const comp = wasm.base.comp;
901 const is_obj = comp.config.output_mode == .Obj;
899 const is_obj = wasm.base.isRelocatable();
902900 return if (is_obj) finishObj(zds, wasm, pt) else finishExe(zds, wasm, pt);
903901 }
904902
......@@ -1276,8 +1274,7 @@ pub const GlobalImport = extern struct {
12761274 const object_global_index = i - first_object_global;
12771275 if (object_global_index < wasm.object_globals.items.len)
12781276 return .{ .object_global = @fromBackingInt(@intCast(object_global_index)) };
1279 const comp = wasm.base.comp;
1280 const is_obj = comp.config.output_mode == .Obj;
1277 const is_obj = wasm.base.isRelocatable();
12811278 const uav_index = object_global_index - wasm.object_globals.items.len;
12821279 if (is_obj) {
12831280 if (uav_index < wasm.uavs_obj.entries.len) {
......@@ -1323,7 +1320,7 @@ pub const GlobalImport = extern struct {
13231320 }
13241321
13251322 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();
13271324 return pack(wasm, if (is_obj) .{
13281325 .uav_obj = @fromBackingInt(@intCast(wasm.uavs_obj.getIndex(ip_index).?)),
13291326 } else .{
......@@ -1332,8 +1329,7 @@ pub const GlobalImport = extern struct {
13321329 }
13331330
13341331 pub fn fromIpNav(wasm: *const Wasm, ip_nav: InternPool.Nav.Index) Resolution {
1335 const comp = wasm.base.comp;
1336 const is_obj = comp.config.output_mode == .Obj;
1332 const is_obj = wasm.base.isRelocatable();
13371333 return pack(wasm, if (is_obj) .{
13381334 .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(ip_nav).?)),
13391335 } else .{
......@@ -1819,8 +1815,7 @@ pub const ObjectDataImport = extern struct {
18191815 else
18201816 object_index - wasm.object_datas.items.len;
18211817
1822 const comp = wasm.base.comp;
1823 const is_obj = comp.config.output_mode == .Obj;
1818 const is_obj = wasm.base.isRelocatable();
18241819 if (is_obj) {
18251820 const nav_index = if (uav_index < wasm.uavs_obj.entries.len)
18261821 return .{ .uav_obj = @fromBackingInt(@intCast(uav_index)) }
......@@ -1863,7 +1858,7 @@ pub const ObjectDataImport = extern struct {
18631858 }
18641859
18651860 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();
18671862 return pack(wasm, if (is_obj) .{
18681863 .uav_obj = @fromBackingInt(@intCast(wasm.uavs_obj.getIndex(ip_index).?)),
18691864 } else .{
......@@ -1872,7 +1867,7 @@ pub const ObjectDataImport = extern struct {
18721867 }
18731868
18741869 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();
18761871 return pack(wasm, if (is_obj) .{
18771872 .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(nav_index).?)),
18781873 } else .{
......@@ -2117,8 +2112,7 @@ pub const DataSegmentId = enum(u32) {
21172112 else
21182113 object_index - wasm.object_data_segments.items.len;
21192114
2120 const comp = wasm.base.comp;
2121 const is_obj = comp.config.output_mode == .Obj;
2115 const is_obj = wasm.base.isRelocatable();
21222116 if (is_obj) {
21232117 const nav_index = if (uav_index < wasm.uavs_obj.entries.len)
21242118 return .{ .uav_obj = @fromBackingInt(@intCast(uav_index)) }
......@@ -2139,8 +2133,7 @@ pub const DataSegmentId = enum(u32) {
21392133 }
21402134
21412135 pub fn fromNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) DataSegmentId {
2142 const comp = wasm.base.comp;
2143 const is_obj = comp.config.output_mode == .Obj;
2136 const is_obj = wasm.base.isRelocatable();
21442137 return pack(wasm, if (is_obj) .{
21452138 .nav_obj = @fromBackingInt(@intCast(wasm.navs_obj.getIndex(nav_index).?)),
21462139 } else .{
......@@ -2717,17 +2710,17 @@ pub const FunctionImportId = enum(u32) {
27172710 /// Asserts not emitting an object, and `Wasm.import_symbols` is false.
27182711 pub fn undefinedAllowed(id: FunctionImportId, wasm: *const Wasm) bool {
27192712 assert(!wasm.import_symbols);
2720 assert(wasm.base.comp.config.output_mode != .Obj);
2713 assert(!wasm.base.isRelocatable());
27212714 return switch (unpack(id, wasm)) {
27222715 .object_function_import => |i| {
27232716 const import = i.value(wasm);
2724 return import.flags.binding == .strong and import.module_name != .none;
2717 return import.flags.binding == .strong;
27252718 },
27262719 .zcu_import => |i| {
27272720 const zcu = wasm.base.comp.zcu.?;
27282721 const ip = &zcu.intern_pool;
27292722 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;
27312724 },
27322725 };
27332726 }
......@@ -3343,6 +3336,7 @@ pub fn createEmpty(
33433336 assert(target.ofmt == .wasm);
33443337
33453338 const output_mode = comp.config.output_mode;
3339 const is_relocatable = output_mode == .Obj or (output_mode == .Lib and comp.config.link_mode == .static);
33463340 const wasi_exec_model = comp.config.wasi_exec_model;
33473341
33483342 const wasm = try arena.create(Wasm);
......@@ -3356,7 +3350,7 @@ pub fn createEmpty(
33563350 // majority of cases, and therefore express "no garbage collection"
33573351 // in terms of setting the no_strip and must_link flags on all
33583352 // symbols.
3359 .gc_sections = options.gc_sections orelse (output_mode != .Obj),
3353 .gc_sections = options.gc_sections orelse !is_relocatable,
33603354 .print_gc_sections = options.print_gc_sections,
33613355 .stack_size = options.stack_size orelse switch (target.os.tag) {
33623356 .freestanding => 1 * 1024 * 1024, // 1 MiB
......@@ -3436,6 +3430,11 @@ fn parseObject(wasm: *Wasm, obj: link.Input.Object) !void {
34363430 };
34373431 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
34393438 var ss: Object.ScratchSpace = .{};
34403439 defer ss.deinit(gpa);
34413440
......@@ -3526,6 +3525,7 @@ pub fn deinit(wasm: *Wasm) void {
35263525 wasm.object_relocations_table.deinit(gpa);
35273526 wasm.object_comdat_symbols.deinit(gpa);
35283527 wasm.objects.deinit(gpa);
3528 wasm.archive_builder.deinit(gpa);
35293529
35303530 wasm.func_types.deinit(gpa);
35313531 wasm.function_exports.deinit(gpa);
......@@ -3575,7 +3575,7 @@ pub fn updateFunc(
35753575 const zcu = pt.zcu;
35763576 const gpa = zcu.gpa;
35773577 const ip = &zcu.intern_pool;
3578 const is_obj = zcu.comp.config.output_mode == .Obj;
3578 const is_obj = wasm.base.isRelocatable();
35793579 const target = &zcu.comp.root_mod.resolved_target.result;
35803580 const owner_nav = zcu.funcInfo(func_index).owner_nav;
35813581 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
36563656 const nav = ip.getNav(nav_index);
36573657 const comp = wasm.base.comp;
36583658 const gpa = comp.gpa;
3659 const is_obj = comp.config.output_mode == .Obj;
3659 const is_obj = wasm.base.isRelocatable();
36603660 const target = &comp.root_mod.resolved_target.result;
36613661
36623662 switch (ip.indexToKey(nav.resolved.?.value)) {
......@@ -3740,7 +3740,7 @@ pub fn updateExports(
37403740 const zcu = pt.zcu;
37413741 const gpa = zcu.gpa;
37423742 const ip = &zcu.intern_pool;
3743 const is_obj = wasm.base.comp.config.output_mode == .Obj;
3743 const is_obj = wasm.base.isRelocatable();
37443744
37453745 for (export_indices) |export_idx| {
37463746 const exp = export_idx.ptr(zcu);
......@@ -3797,7 +3797,11 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void {
37973797 .dso => unreachable,
37983798 .tbd => unreachable,
37993799 .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 },
38013805 }
38023806}
38033807
......@@ -3811,7 +3815,7 @@ pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.Error!void {
38113815 const comp = wasm.base.comp;
38123816 const gpa = comp.gpa;
38133817 const rdynamic = comp.config.rdynamic;
3814 const is_obj = comp.config.output_mode == .Obj;
3818 const is_obj = wasm.base.isRelocatable();
38153819
38163820 assert(wasm.missing_exports.entries.len == 0);
38173821 for (wasm.export_symbol_names) |exp_name| {
......@@ -3915,7 +3919,7 @@ pub fn markFunctionImport(
39153919
39163920 const comp = wasm.base.comp;
39173921 const gpa = comp.gpa;
3918 const is_obj = comp.config.output_mode == .Obj;
3922 const is_obj = wasm.base.isRelocatable();
39193923
39203924 try wasm.functions.ensureUnusedCapacity(gpa, 1);
39213925
......@@ -3949,7 +3953,7 @@ fn markFunction(wasm: *Wasm, i: ObjectFunctionIndex, override_export: bool) link
39493953 if (gop.found_existing) return;
39503954
39513955 const rdynamic = comp.config.rdynamic;
3952 const is_obj = comp.config.output_mode == .Obj;
3956 const is_obj = wasm.base.isRelocatable();
39533957 const function = i.ptr(wasm);
39543958 try markObject(wasm, function.object_index);
39553959
......@@ -3991,7 +3995,7 @@ fn markGlobalImport(
39913995
39923996 const comp = wasm.base.comp;
39933997 const gpa = comp.gpa;
3994 const is_obj = comp.config.output_mode == .Obj;
3998 const is_obj = wasm.base.isRelocatable();
39953999
39964000 try wasm.globals.ensureUnusedCapacity(gpa, 1);
39974001
......@@ -4034,7 +4038,7 @@ fn markGlobal(wasm: *Wasm, i: ObjectGlobalIndex, override_export: bool) link.Err
40344038 if (gop.found_existing) return;
40354039
40364040 const rdynamic = comp.config.rdynamic;
4037 const is_obj = comp.config.output_mode == .Obj;
4041 const is_obj = wasm.base.isRelocatable();
40384042 const global = i.ptr(wasm);
40394043 try markObject(wasm, global.object_index);
40404044
......@@ -4057,7 +4061,7 @@ pub fn markTableImport(
40574061
40584062 const comp = wasm.base.comp;
40594063 const gpa = comp.gpa;
4060 const is_obj = comp.config.output_mode == .Obj;
4064 const is_obj = wasm.base.isRelocatable();
40614065
40624066 try wasm.tables.ensureUnusedCapacity(gpa, 1);
40634067
......@@ -4103,7 +4107,7 @@ pub fn markDataImport(
41034107
41044108 const comp = wasm.base.comp;
41054109 const gpa = comp.gpa;
4106 const is_obj = comp.config.output_mode == .Obj;
4110 const is_obj = wasm.base.isRelocatable();
41074111
41084112 if (import.resolution == .unresolved) {
41094113 if (!is_obj) {
......@@ -4682,7 +4686,7 @@ pub fn addNavReloc(
46824686 const ip = &zcu.intern_pool;
46834687 const gpa = comp.gpa;
46844688
4685 const is_obj = comp.config.output_mode == .Obj;
4689 const is_obj = wasm.base.isRelocatable();
46864690
46874691 if (nav_ty.zigTypeTag(zcu) == .@"fn") {
46884692 const gop = try wasm.zcu_indirect_function_set.getOrPut(gpa, nav_index);
......@@ -4751,7 +4755,7 @@ pub fn addUavReloc(
47514755 gop.value_ptr.* = if (gop.found_existing) gop.value_ptr.maxStrict(this_align) else this_align;
47524756 }
47534757
4754 if (comp.config.output_mode == .Obj) {
4758 if (wasm.base.isRelocatable()) {
47554759 const gop = try wasm.uavs_obj.getOrPut(gpa, uav_val);
47564760 if (!gop.found_existing) gop.value_ptr.* = undefined; // to avoid recursion, `ZcuDataStarts` will lower the value later
47574761 try wasm.zcu_relocations.append(gpa, .{
......@@ -4782,7 +4786,7 @@ pub fn addUavReloc(
47824786pub fn refNavObj(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsObjIndex {
47834787 const comp = wasm.base.comp;
47844788 const gpa = comp.gpa;
4785 assert(comp.config.output_mode == .Obj);
4789 assert(wasm.base.isRelocatable());
47864790 const gop = try wasm.navs_obj.getOrPut(gpa, nav_index);
47874791 if (!gop.found_existing) gop.value_ptr.* = .{
47884792 // Lowering the value is delayed to avoid recursion.
......@@ -4795,7 +4799,7 @@ pub fn refNavObj(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsObjIndex {
47954799pub fn refNavExe(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsExeIndex {
47964800 const comp = wasm.base.comp;
47974801 const gpa = comp.gpa;
4798 assert(comp.config.output_mode != .Obj);
4802 assert(!wasm.base.isRelocatable());
47994803 const gop = try wasm.navs_exe.getOrPut(gpa, nav_index);
48004804 if (gop.found_existing) {
48014805 gop.value_ptr.count += 1;
......@@ -4812,8 +4816,7 @@ pub fn refNavExe(wasm: *Wasm, nav_index: InternPool.Nav.Index) !NavsExeIndex {
48124816/// Asserts it is called after `Flush.data_segments` is fully populated and sorted.
48134817pub fn uavAddr(wasm: *const Wasm, ip_index: InternPool.Index) u32 {
48144818 assert(wasm.flush_buffer.memory_layout_finished);
4815 const comp = wasm.base.comp;
4816 assert(comp.config.output_mode != .Obj);
4819 assert(!wasm.base.isRelocatable());
48174820 const uav_index: UavsExeIndex = @fromBackingInt(@intCast(wasm.uavs_exe.getIndex(ip_index).?));
48184821 const ds_id: DataSegmentId = .pack(wasm, .{ .uav_exe = uav_index });
48194822 return wasm.flush_buffer.data_segments.get(ds_id).?;
......@@ -4834,7 +4837,7 @@ pub fn syntheticDataAddr(wasm: *const Wasm, resolution: ObjectDataImport.Resolut
48344837pub fn navAddr(wasm: *const Wasm, nav_index: InternPool.Nav.Index) u32 {
48354838 assert(wasm.flush_buffer.memory_layout_finished);
48364839 const comp = wasm.base.comp;
4837 assert(comp.config.output_mode != .Obj);
4840 assert(!wasm.base.isRelocatable());
48384841 if (wasm.navs_exe.getIndex(nav_index)) |i| {
48394842 const navs_exe_index: NavsExeIndex = @fromBackingInt(@intCast(i));
48404843 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 {
48884891/// Asserts it is called after `Flush.data_segments` is fully populated and sorted.
48894892pub fn errorNameTableAddr(wasm: *Wasm) u32 {
48904893 assert(wasm.flush_buffer.memory_layout_finished);
4891 const comp = wasm.base.comp;
4892 assert(comp.config.output_mode != .Obj);
4894 assert(!wasm.base.isRelocatable());
48934895 return wasm.flush_buffer.data_segments.get(.__zig_error_name_table).?;
48944896}
48954897
48964898pub fn tagIndexTableAddr(wasm: *Wasm, ip_index: InternPool.Index) u32 {
48974899 assert(wasm.flush_buffer.memory_layout_finished);
4898 const comp = wasm.base.comp;
4899 assert(comp.config.output_mode != .Obj);
4900 assert(!wasm.base.isRelocatable());
49004901 const f = &wasm.flush_buffer;
49014902 const table_base_addr = f.data_segments.get(.__zig_tag_name_table).?;
49024903 return table_base_addr + wasm.tagIndexTableOffset(ip_index);
src/link/Wasm/Archive.zig+138
......@@ -68,6 +68,143 @@ const Header = extern struct {
6868 }
6969};
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
71208pub fn deinit(archive: *Archive, gpa: Allocator) void {
72209 deinitToc(gpa, &archive.toc);
73210 archive.* = undefined;
......@@ -102,6 +239,7 @@ pub fn parse(gpa: Allocator, file_contents: []const u8) !Archive {
102239
103240 const sym_tab = file_contents[pos..][0 .. sym_tab_size - 4 - symbol_positions_size];
104241 pos += sym_tab.len;
242 pos = mem.alignForward(usize, pos, 2);
105243
106244 var toc: Toc = .empty;
107245 errdefer deinitToc(gpa, &toc);
src/link/Wasm/Flush.zig+27-4
......@@ -247,7 +247,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
247247 .wasm64 => true,
248248 else => unreachable,
249249 };
250 const is_obj = comp.config.output_mode == .Obj;
250 const is_obj = wasm.base.isRelocatable();
251251 const allow_undefined = is_obj or wasm.import_symbols;
252252 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 {
17251725
17261726 // Finally, write the entire binary into the file.
17271727 var file_writer = wasm.base.file.?.writer(io, &.{});
1728 file_writer.interface.writeAll(binary_bytes.items) catch |err| switch (err) {
1729 error.WriteFailed => return file_writer.err.?,
1730 };
1728 if (wasm.base.isStaticLib()) {
1729 const builder = &wasm.archive_builder;
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 }
17311754 file_writer.end() catch |err| switch (err) {
17321755 error.WriteFailed => return file_writer.err.?,
17331756 else => |e| return e,
test/behavior/atomics.zig+1
......@@ -184,6 +184,7 @@ fn testAtomicStore() !void {
184184}
185185
186186test "atomicrmw with floats" {
187 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
187188 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
188189 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
189190 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/optional.zig+34
......@@ -58,6 +58,40 @@ fn testNullPtrsEql() !void {
5858 try expect(&number == x);
5959}
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
6195test "optional with zero-bit type" {
6296 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
6397 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
test/behavior/switch.zig+125-23
......@@ -47,34 +47,136 @@ test "switch arbitrary int size" {
4747 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; // TODO
4848 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
4949
50 try expect(testSwitchArbInt(u64, 0) == 0);
51 try expect(testSwitchArbInt(u64, 12) == 1);
52 try expect(testSwitchArbInt(u64, maxInt(u64)) == 2);
53 try expect(testSwitchArbInt(u64, 5555) == 3);
54
55 try expect(testSwitchArbInt(i64, minInt(i64)) == 0);
56 try expect(testSwitchArbInt(i64, 12) == 1);
57 try expect(testSwitchArbInt(i64, maxInt(i64)) == 2);
58 try expect(testSwitchArbInt(i64, -1000) == 3);
50 const S = struct {
51 fn testSwitchArbInt(comptime T: type, x: T) u32 {
52 return switch (x) {
53 minInt(T) => 0,
54 10...15 => 1,
55 maxInt(T) => 2,
56 else => 3,
57 };
58 }
5959
60 try expect(testSwitchArbInt(u128, 0) == 0);
61 try expect(testSwitchArbInt(u128, 12) == 1);
62 try expect(testSwitchArbInt(u128, maxInt(u128)) == 2);
63 try expect(testSwitchArbInt(u128, 5555) == 3);
60 fn doTheTest() !void {
61 try expect(testSwitchArbInt(u64, 0) == 0);
62 try expect(testSwitchArbInt(u64, 12) == 1);
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);
66 try expect(testSwitchArbInt(i128, 12) == 1);
67 try expect(testSwitchArbInt(i128, maxInt(i128)) == 2);
68 try expect(testSwitchArbInt(i128, -1000) == 3);
83 try S.doTheTest();
84 try comptime S.doTheTest();
6985}
7086
71fn testSwitchArbInt(comptime T: type, x: T) u32 {
72 return switch (x) {
73 minInt(T) => 0,
74 10...15 => 1,
75 maxInt(T) => 2,
76 else => 3,
87test "dense switch" {
88 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
89 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
90 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
91 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
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 }
77176 };
177
178 try S.doTheTest();
179 try comptime S.doTheTest();
78180}
79181
80182test "implicit comptime switch" {
test/tests.zig+21
......@@ -1601,6 +1601,27 @@ const module_test_targets = blk: {
16011601 .{
16021602 .target = .{
16031603 .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 },
16041625 .os_tag = .wasi,
16051626 .abi = .none,
16061627 },