authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-07-02 23:54:41+02:00
committergravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-07-03 22:14:13+02:00
log25fcf03a678c4fc357d1342322cfe7ca058d9c0f
treed5fde2e5e7720704c4d62a1d29cb784ae6ae01ed
parent2f7e082381e64bbcdd06cf8f06eb84a9c8ad67de

stage2-wasm: support .is_named_enum_value


6 files changed, 118 insertions(+), 73 deletions(-)

src/codegen/wasm/CodeGen.zig+35-8
...@@ -1856,10 +1856,11 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -1856,10 +1856,11 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
1856 .c_va_end => try cg.airVaEnd(inst),1856 .c_va_end => try cg.airVaEnd(inst),
1857 .c_va_start => try cg.airVaStart(inst),1857 .c_va_start => try cg.airVaStart(inst),
18581858
1859 .is_named_enum_value => try cg.airIsNamedEnumValue(inst),
1860
1859 .err_return_trace,1861 .err_return_trace,
1860 .set_err_return_trace,1862 .set_err_return_trace,
1861 .save_err_return_trace_index,1863 .save_err_return_trace_index,
1862 .is_named_enum_value,
1863 .addrspace_cast,1864 .addrspace_cast,
1864 => |tag| return cg.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),1865 => |tag| return cg.fail("TODO: Implement wasm inst: {s}", .{@tagName(tag)}),
18651866
...@@ -7279,12 +7280,37 @@ fn airTagName(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7279,12 +7280,37 @@ fn airTagName(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7279 const operand = try cg.resolveInst(un_op);7280 const operand = try cg.resolveInst(un_op);
7280 const enum_ty = cg.typeOf(un_op);7281 const enum_ty = cg.typeOf(un_op);
72817282
7282 const result_ptr = try cg.allocStack(cg.typeOfIndex(inst));7283 try cg.addInst(.{ .tag = .enum_tag_name_table_ref, .data = .{ .ip_index = enum_ty.toIntern() } });
7283 try cg.lowerToStack(result_ptr);7284 try cg.lowerToStack(operand);
7285 try cg.addInst(.{ .tag = .call_tag_index, .data = .{ .ip_index = enum_ty.toIntern() } });
7286
7287 switch (cg.ptr_size) {
7288 .wasm32 => {
7289 try cg.addImm32(@intCast(8));
7290 try cg.addTag(.i32_mul);
7291 try cg.addTag(.i32_add);
7292 },
7293 .wasm64 => {
7294 try cg.addImm64(8);
7295 try cg.addTag(.i64_mul);
7296 try cg.addTag(.i64_add);
7297 },
7298 }
7299
7300 return cg.finishAir(inst, .stack, &.{un_op});
7301}
7302
7303fn airIsNamedEnumValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7304 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
7305 const operand = try cg.resolveInst(un_op);
7306 const enum_ty = cg.typeOf(un_op);
7307
7284 try cg.lowerToStack(operand);7308 try cg.lowerToStack(operand);
7285 try cg.addInst(.{ .tag = .call_tag_name, .data = .{ .ip_index = enum_ty.toIntern() } });7309 try cg.addInst(.{ .tag = .call_tag_index, .data = .{ .ip_index = enum_ty.toIntern() } });
7310 try cg.addImm32(~@as(u32, 0));
7311 try cg.addTag(.i32_ne);
72867312
7287 return cg.finishAir(inst, result_ptr, &.{un_op});7313 return cg.finishAir(inst, .stack, &.{un_op});
7288}7314}
72897315
7290fn airErrorSetHasValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {7316fn airErrorSetHasValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
...@@ -7313,7 +7339,7 @@ fn airErrorSetHasValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7313,7 +7339,7 @@ fn airErrorSetHasValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7313 }7339 }
7314 if (highest) |*h| {7340 if (highest) |*h| {
7315 if (err_int > h.*) {7341 if (err_int > h.*) {
7316 highest = err_int;7342 h.* = err_int;
7317 }7343 }
7318 } else {7344 } else {
7319 highest = err_int;7345 highest = err_int;
...@@ -7336,10 +7362,10 @@ fn airErrorSetHasValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7336,10 +7362,10 @@ fn airErrorSetHasValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
73367362
7337 // Account for default branch so always add '1'7363 // Account for default branch so always add '1'
7338 const depth = @as(u32, @intCast(highest.? - lowest.? + 1));7364 const depth = @as(u32, @intCast(highest.? - lowest.? + 1));
7339 const jump_table: Mir.JumpTable = .{ .length = depth };7365 const jump_table: Mir.JumpTable = .{ .length = depth + 1 };
7340 const table_extra_index = try cg.addExtra(jump_table);7366 const table_extra_index = try cg.addExtra(jump_table);
7341 try cg.addInst(.{ .tag = .br_table, .data = .{ .payload = table_extra_index } });7367 try cg.addInst(.{ .tag = .br_table, .data = .{ .payload = table_extra_index } });
7342 try cg.mir_extra.ensureUnusedCapacity(cg.gpa, depth);7368 try cg.mir_extra.ensureUnusedCapacity(cg.gpa, depth + 1);
73437369
7344 var value: u32 = lowest.?;7370 var value: u32 = lowest.?;
7345 while (value <= highest.?) : (value += 1) {7371 while (value <= highest.?) : (value += 1) {
...@@ -7351,6 +7377,7 @@ fn airErrorSetHasValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7351,6 +7377,7 @@ fn airErrorSetHasValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7351 };7377 };
7352 cg.mir_extra.appendAssumeCapacity(idx);7378 cg.mir_extra.appendAssumeCapacity(idx);
7353 }7379 }
7380 cg.mir_extra.appendAssumeCapacity(0); // outside lowest...highest
7354 try cg.endBlock();7381 try cg.endBlock();
73557382
7356 // 'false' branch (i.e. error set does not have value7383 // 'false' branch (i.e. error set does not have value
src/codegen/wasm/Emit.zig+18-3
...@@ -220,25 +220,40 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -220,25 +220,40 @@ pub fn lowerToCode(emit: *Emit) Error!void {
220 continue :loop tags[inst];220 continue :loop tags[inst];
221 },221 },
222222
223 .call_tag_name => {223 .call_tag_index => {
224 try code.ensureUnusedCapacity(gpa, 6);224 try code.ensureUnusedCapacity(gpa, 6);
225 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.call));225 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.call));
226 if (is_obj) {226 if (is_obj) {
227 try wasm.out_relocs.append(gpa, .{227 try wasm.out_relocs.append(gpa, .{
228 .offset = @intCast(code.items.len),228 .offset = @intCast(code.items.len),
229 .pointee = .{ .symbol_index = try wasm.tagNameSymbolIndex(datas[inst].ip_index) },229 .pointee = .{ .symbol_index = try wasm.tagTableIndexSymbolIndex(datas[inst].ip_index) },
230 .tag = .function_index_leb,230 .tag = .function_index_leb,
231 .addend = 0,231 .addend = 0,
232 });232 });
233 code.appendNTimesAssumeCapacity(0, 5);233 code.appendNTimesAssumeCapacity(0, 5);
234 } else {234 } else {
235 appendOutputFunctionIndex(code, .fromTagNameType(wasm, datas[inst].ip_index));235 appendOutputFunctionIndex(code, .fromTagIndexType(wasm, datas[inst].ip_index));
236 }236 }
237237
238 inst += 1;238 inst += 1;
239 continue :loop tags[inst];239 continue :loop tags[inst];
240 },240 },
241241
242 .enum_tag_name_table_ref => {
243 try code.ensureUnusedCapacity(gpa, 11);
244 const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const;
245 code.appendAssumeCapacity(@intFromEnum(opcode));
246 if (is_obj) {
247 @panic("TODO");
248 } else {
249 const addr: u32 = wasm.tagIndexTableAddr(datas[inst].ip_index);
250 writeSleb128(code, addr);
251
252 inst += 1;
253 continue :loop tags[inst];
254 }
255 },
256
242 .call_intrinsic => {257 .call_intrinsic => {
243 // Although this currently uses `wasm.internString`, note that it258 // Although this currently uses `wasm.internString`, note that it
244 // *could* be changed to directly index into a preloaded strings259 // *could* be changed to directly index into a preloaded strings
src/codegen/wasm/Mir.zig+7-2
...@@ -164,9 +164,14 @@ pub const Inst = struct {...@@ -164,9 +164,14 @@ pub const Inst = struct {
164 call_indirect,164 call_indirect,
165 /// Calls a function by its index.165 /// Calls a function by its index.
166 ///166 ///
167 /// The function is the auto-generated tag name function for the type167 /// The function is the auto-generated tag index function for the type
168 /// provided in `ip_index`.168 /// provided in `ip_index`.
169 call_tag_name,169 call_tag_index,
170 /// Lowers to an i32_const (wasm32) or i64_const (wasm64) containing
171 /// the base address of the table of enum tag names slices.
172 ///
173 /// Uses `ip_index`.
174 enum_tag_name_table_ref,
170 /// Lowers to a `call` instruction, using `intrinsic`.175 /// Lowers to a `call` instruction, using `intrinsic`.
171 call_intrinsic,176 call_intrinsic,
172 /// Pops a value from the stack, and discards it.177 /// Pops a value from the stack, and discards it.
src/link/Wasm.zig+14-6
...@@ -348,7 +348,7 @@ pub const FunctionIndex = enum(u32) {...@@ -348,7 +348,7 @@ pub const FunctionIndex = enum(u32) {
348 return fromResolution(wasm, .fromIpNav(wasm, nav_index));348 return fromResolution(wasm, .fromIpNav(wasm, nav_index));
349 }349 }
350350
351 pub fn fromTagNameType(wasm: *const Wasm, tag_type: InternPool.Index) ?FunctionIndex {351 pub fn fromTagIndexType(wasm: *const Wasm, tag_type: InternPool.Index) ?FunctionIndex {
352 const zcu_func: ZcuFunc.Index = @enumFromInt(wasm.zcu_funcs.getIndex(tag_type) orelse return null);352 const zcu_func: ZcuFunc.Index = @enumFromInt(wasm.zcu_funcs.getIndex(tag_type) orelse return null);
353 return fromResolution(wasm, .pack(wasm, .{ .zcu_func = zcu_func }));353 return fromResolution(wasm, .pack(wasm, .{ .zcu_func = zcu_func }));
354 }354 }
...@@ -423,8 +423,8 @@ pub const OutputFunctionIndex = enum(u32) {...@@ -423,8 +423,8 @@ pub const OutputFunctionIndex = enum(u32) {
423 return fromIpIndex(wasm, nav.resolved.?.value);423 return fromIpIndex(wasm, nav.resolved.?.value);
424 }424 }
425425
426 pub fn fromTagNameType(wasm: *const Wasm, tag_type: InternPool.Index) OutputFunctionIndex {426 pub fn fromTagIndexType(wasm: *const Wasm, tag_type: InternPool.Index) OutputFunctionIndex {
427 return fromFunctionIndex(wasm, FunctionIndex.fromTagNameType(wasm, tag_type).?);427 return fromFunctionIndex(wasm, FunctionIndex.fromTagIndexType(wasm, tag_type).?);
428 }428 }
429429
430 pub fn fromSymbolName(wasm: *const Wasm, name: String) OutputFunctionIndex {430 pub fn fromSymbolName(wasm: *const Wasm, name: String) OutputFunctionIndex {
...@@ -891,8 +891,6 @@ pub const ZcuFunc = union {...@@ -891,8 +891,6 @@ pub const ZcuFunc = union {
891 pub const TagName = extern struct {891 pub const TagName = extern struct {
892 symbol_name: String,892 symbol_name: String,
893 type_index: FunctionType.Index,893 type_index: FunctionType.Index,
894 /// Index into `Wasm.tag_name_offs`.
895 table_index: u32,
896 };894 };
897895
898 /// Index into `Wasm.zcu_funcs`.896 /// Index into `Wasm.zcu_funcs`.
...@@ -4015,7 +4013,7 @@ pub fn stackPointerSymbolIndex(wasm: *Wasm) Allocator.Error!SymbolTableIndex {...@@ -4015,7 +4013,7 @@ pub fn stackPointerSymbolIndex(wasm: *Wasm) Allocator.Error!SymbolTableIndex {
4015 return @enumFromInt(gop.index);4013 return @enumFromInt(gop.index);
4016}4014}
40174015
4018pub fn tagNameSymbolIndex(wasm: *Wasm, ip_index: InternPool.Index) Allocator.Error!SymbolTableIndex {4016pub fn tagTableIndexSymbolIndex(wasm: *Wasm, ip_index: InternPool.Index) Allocator.Error!SymbolTableIndex {
4019 const comp = wasm.base.comp;4017 const comp = wasm.base.comp;
4020 assert(comp.config.output_mode == .Obj);4018 assert(comp.config.output_mode == .Obj);
4021 const gpa = comp.gpa;4019 const gpa = comp.gpa;
...@@ -4173,6 +4171,16 @@ pub fn errorNameTableAddr(wasm: *Wasm) u32 {...@@ -4173,6 +4171,16 @@ pub fn errorNameTableAddr(wasm: *Wasm) u32 {
4173 return wasm.flush_buffer.data_segments.get(.__zig_error_name_table).?;4171 return wasm.flush_buffer.data_segments.get(.__zig_error_name_table).?;
4174}4172}
41754173
4174pub fn tagIndexTableAddr(wasm: *Wasm, ip_index: InternPool.Index) u32 {
4175 assert(wasm.flush_buffer.memory_layout_finished);
4176 const comp = wasm.base.comp;
4177 assert(comp.config.output_mode != .Obj);
4178 const f = &wasm.flush_buffer;
4179 const table_base_addr = f.data_segments.get(.__zig_tag_name_table).?;
4180 const table_index = f.enum_tag_name_table.get(ip_index).?;
4181 return table_base_addr + table_index * 8;
4182}
4183
4176fn convertZcuFnType(4184fn convertZcuFnType(
4177 comp: *Compilation,4185 comp: *Compilation,
4178 cc: std.lang.CallingConvention,4186 cc: std.lang.CallingConvention,
src/link/Wasm/Flush.zig+43-53
...@@ -41,6 +41,8 @@ indirect_function_table: std.array_hash_map.Auto(Wasm.OutputFunctionIndex, void)...@@ -41,6 +41,8 @@ indirect_function_table: std.array_hash_map.Auto(Wasm.OutputFunctionIndex, void)
41/// A subset of the full interned function type list created only during flush.41/// A subset of the full interned function type list created only during flush.
42func_types: std.array_hash_map.Auto(Wasm.FunctionType.Index, void) = .empty,42func_types: std.array_hash_map.Auto(Wasm.FunctionType.Index, void) = .empty,
4343
44enum_tag_name_table: std.array_hash_map.Auto(InternPool.Index, u32) = .empty,
45
44/// For debug purposes only.46/// For debug purposes only.
45memory_layout_finished: bool = false,47memory_layout_finished: bool = false,
4648
...@@ -90,6 +92,7 @@ pub fn clear(f: *Flush) void {...@@ -90,6 +92,7 @@ pub fn clear(f: *Flush) void {
90 f.binary_bytes.clearRetainingCapacity();92 f.binary_bytes.clearRetainingCapacity();
91 f.indirect_function_table.clearRetainingCapacity();93 f.indirect_function_table.clearRetainingCapacity();
92 f.func_types.clearRetainingCapacity();94 f.func_types.clearRetainingCapacity();
95 f.enum_tag_name_table.clearRetainingCapacity();
93 f.memory_layout_finished = false;96 f.memory_layout_finished = false;
94}97}
9598
...@@ -103,6 +106,7 @@ pub fn deinit(f: *Flush, gpa: Allocator) void {...@@ -103,6 +106,7 @@ pub fn deinit(f: *Flush, gpa: Allocator) void {
103 f.data_imports.deinit(gpa);106 f.data_imports.deinit(gpa);
104 f.indirect_function_table.deinit(gpa);107 f.indirect_function_table.deinit(gpa);
105 f.func_types.deinit(gpa);108 f.func_types.deinit(gpa);
109 f.enum_tag_name_table.deinit(gpa);
106 f.* = undefined;110 f.* = undefined;
107}111}
108112
...@@ -143,17 +147,24 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -143,17 +147,24 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
143 try wasm.markFunctionImport(symbol_name, i.value(wasm), i);147 try wasm.markFunctionImport(symbol_name, i.value(wasm), i);
144 log.debug("markFunctionImport intrinsic {d}={t}", .{ i, data.intrinsic });148 log.debug("markFunctionImport intrinsic {d}={t}", .{ i, data.intrinsic });
145 },149 },
146 .call_tag_name => {150 .call_tag_index => {
147 assert(ip.indexToKey(data.ip_index) == .enum_type);151 assert(ip.indexToKey(data.ip_index) == .enum_type);
148 const gop = try wasm.zcu_funcs.getOrPut(gpa, data.ip_index);152 const gop = try wasm.zcu_funcs.getOrPut(gpa, data.ip_index);
149 if (!gop.found_existing) {153 if (!gop.found_existing) {
150 wasm.tag_name_table_ref_count += 1;
151 const int_tag_ty = Zcu.Type.fromInterned(data.ip_index).intTagType(zcu);154 const int_tag_ty = Zcu.Type.fromInterned(data.ip_index).intTagType(zcu);
152 gop.value_ptr.* = .{ .tag_name = .{155 gop.value_ptr.* = .{ .tag_name = .{
153 .symbol_name = try wasm.internStringFmt("__zig_tag_name_{d}", .{data.ip_index}),156 .symbol_name = try wasm.internStringFmt("__zig_tag_index_{d}", .{data.ip_index}),
154 .type_index = try wasm.internFunctionType(.auto, &.{int_tag_ty.ip_index}, .slice_const_u8_sentinel_0, false, target),157 .type_index = try wasm.internFunctionType(.auto, &.{int_tag_ty.ip_index}, .u32, false, target),
155 .table_index = @intCast(wasm.tag_name_offs.items.len),
156 } };158 } };
159 }
160 try wasm.functions.put(gpa, .fromZcuFunc(wasm, @enumFromInt(gop.index)), {});
161 },
162 .enum_tag_name_table_ref => {
163 assert(ip.indexToKey(data.ip_index) == .enum_type);
164 const gop = try f.enum_tag_name_table.getOrPut(gpa, data.ip_index);
165 if (!gop.found_existing) {
166 wasm.tag_name_table_ref_count += 1;
167 gop.value_ptr.* = @intCast(wasm.tag_name_offs.items.len);
157 const tag_names = ip.loadEnumType(data.ip_index).field_names;168 const tag_names = ip.loadEnumType(data.ip_index).field_names;
158 for (tag_names.get(ip)) |tag_name| {169 for (tag_names.get(ip)) |tag_name| {
159 const slice = tag_name.toSlice(ip);170 const slice = tag_name.toSlice(ip);
...@@ -161,7 +172,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -161,7 +172,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
161 try wasm.tag_name_bytes.appendSlice(gpa, slice[0 .. slice.len + 1]);172 try wasm.tag_name_bytes.appendSlice(gpa, slice[0 .. slice.len + 1]);
162 }173 }
163 }174 }
164 try wasm.functions.put(gpa, .fromZcuFunc(wasm, @enumFromInt(gop.index)), {});
165 },175 },
166 else => continue,176 else => continue,
167 };177 };
...@@ -874,7 +884,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -874,7 +884,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
874 const ip_index = i.key(wasm).*;884 const ip_index = i.key(wasm).*;
875 switch (ip.indexToKey(ip_index)) {885 switch (ip.indexToKey(ip_index)) {
876 .enum_type => {886 .enum_type => {
877 try emitTagNameFunction(wasm, binary_bytes, f.data_segments.get(.__zig_tag_name_table).?, i.value(wasm).tag_name.table_index, ip_index);887 try emitTagIndexFunction(wasm, binary_bytes, ip_index);
878 },888 },
879 else => {889 else => {
880 const func = i.value(wasm).function;890 const func = i.value(wasm).function;
...@@ -1856,11 +1866,9 @@ fn emitStartSection(gpa: Allocator, bytes: *ArrayList(u8), i: Wasm.OutputFunctio...@@ -1856,11 +1866,9 @@ fn emitStartSection(gpa: Allocator, bytes: *ArrayList(u8), i: Wasm.OutputFunctio
1856 replaceVecSectionHeader(bytes, header_offset, .start, @intFromEnum(i));1866 replaceVecSectionHeader(bytes, header_offset, .start, @intFromEnum(i));
1857}1867}
18581868
1859fn emitTagNameFunction(1869fn emitTagIndexFunction(
1860 wasm: *Wasm,1870 wasm: *Wasm,
1861 code: *ArrayList(u8),1871 code: *ArrayList(u8),
1862 table_base_addr: u32,
1863 table_index: u32,
1864 enum_type_ip: InternPool.Index,1872 enum_type_ip: InternPool.Index,
1865) !void {1873) !void {
1866 const comp = wasm.base.comp;1874 const comp = wasm.base.comp;
...@@ -1870,36 +1878,37 @@ fn emitTagNameFunction(...@@ -1870,36 +1878,37 @@ fn emitTagNameFunction(
1870 const enum_type = ip.loadEnumType(enum_type_ip);1878 const enum_type = ip.loadEnumType(enum_type_ip);
1871 const tag_values = enum_type.field_values.get(ip);1879 const tag_values = enum_type.field_values.get(ip);
18721880
1873 const slice_abi_size = 8;
1874 const encoded_alignment = @ctz(@as(u32, 4));
1875
1876 if (tag_values.len == 0) {1881 if (tag_values.len == 0) {
1877 // Auto-numbered, therefore a direct table lookup.1882 // Auto-numbered
1883
1884 const len = enum_type.field_names.len;
18781885
1879 try code.ensureUnusedCapacity(1886 try code.ensureUnusedCapacity(gpa, 13 + 5 * 2);
1880 gpa,
1881 6 * @sizeOf(std.wasm.Opcode) +
1882 7 * 5 + // appendReservedUleb32
1883 1 * 6, // appendReservedI32Const
1884 );
18851887
1886 appendReservedUleb32(code, 0); // no locals1888 appendReservedUleb32(code, 0); // no locals
18871889
1890 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.block));
1891 code.appendAssumeCapacity(@intFromEnum(std.wasm.BlockType.empty));
1892
1888 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get));1893 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get));
1889 appendReservedUleb32(code, 0);1894 appendReservedUleb32(code, 0);
18901895
1891 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get));1896 appendReservedI32Const(code, len);
1892 appendReservedUleb32(code, 1);1897
1898 // if < len -> break out of block
1899 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_lt_u));
18931900
1894 appendReservedI32Const(code, slice_abi_size);1901 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.br_if));
1895 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_mul));1902 appendReservedUleb32(code, 0);
18961903
1897 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_load));1904 // invalid -> return -1
1898 appendReservedUleb32(code, encoded_alignment);1905 appendReservedI32Const(code, ~@as(u32, 0));
1899 appendReservedUleb32(code, table_base_addr + table_index * 8);1906 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.@"return"));
19001907
1901 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_store));1908 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));
1902 appendReservedUleb32(code, encoded_alignment);1909
1910 // valid -> return input
1911 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get));
1903 appendReservedUleb32(code, 0);1912 appendReservedUleb32(code, 0);
19041913
1905 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));1914 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));
...@@ -1920,13 +1929,6 @@ fn emitTagNameFunction(...@@ -1920,13 +1929,6 @@ fn emitTagNameFunction(
19201929
1921 appendReservedUleb32(code, 0); // no locals1930 appendReservedUleb32(code, 0); // no locals
19221931
1923 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get));
1924 appendReservedUleb32(code, 0);
1925
1926 // Outer block that computes table offset.
1927 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.block));
1928 code.appendAssumeCapacity(@intFromEnum(std.wasm.BlockType.i32));
1929
1930 for (tag_values, 0..) |tag_value, tag_index| {1932 for (tag_values, 0..) |tag_value, tag_index| {
1931 // block for this if case1933 // block for this if case
1932 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.block));1934 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.block));
...@@ -1946,7 +1948,7 @@ fn emitTagNameFunction(...@@ -1946,7 +1948,7 @@ fn emitTagNameFunction(
19461948
1947 for (0..num_limbs) |limb_index| {1949 for (0..num_limbs) |limb_index| {
1948 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get));1950 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get));
1949 appendReservedUleb32(code, 1);1951 appendReservedUleb32(code, 0);
19501952
1951 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_load));1953 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_load));
1952 appendReservedUleb32(code, @ctz(@as(u32, 8)));1954 appendReservedUleb32(code, @ctz(@as(u32, 8)));
...@@ -1960,7 +1962,7 @@ fn emitTagNameFunction(...@@ -1960,7 +1962,7 @@ fn emitTagNameFunction(
1960 }1962 }
1961 } else {1963 } else {
1962 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get));1964 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get));
1963 appendReservedUleb32(code, 1);1965 appendReservedUleb32(code, 0);
19641966
1965 switch (int_info.bits) {1967 switch (int_info.bits) {
1966 0...32 => {1968 0...32 => {
...@@ -1986,26 +1988,14 @@ fn emitTagNameFunction(...@@ -1986,26 +1988,14 @@ fn emitTagNameFunction(
1986 appendReservedUleb32(code, 0);1988 appendReservedUleb32(code, 0);
1987 }1989 }
19881990
1989 // Put the table offset of the result on the stack.1991 appendReservedI32Const(code, @intCast(tag_index));
1990 appendReservedI32Const(code, @intCast(tag_index * slice_abi_size));
1991
1992 // break outside blocks
1993 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.br));
1994 appendReservedUleb32(code, 1);
19951992
1993 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.@"return"));
1996 // end the block for this case1994 // end the block for this case
1997 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));1995 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));
1998 }1996 }
1999 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.@"unreachable"));
2000 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));
2001
2002 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_load));
2003 appendReservedUleb32(code, encoded_alignment);
2004 appendReservedUleb32(code, table_base_addr + table_index * 8);
20051997
2006 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_store));1998 appendReservedI32Const(code, ~@as(u32, 0));
2007 appendReservedUleb32(code, encoded_alignment);
2008 appendReservedUleb32(code, 0);
20091999
2010 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));2000 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end));
2011}2001}
src/target.zig+1-1
...@@ -937,7 +937,7 @@ pub inline fn backendSupportsFeature(backend: std.lang.CompilerBackend, comptime...@@ -937,7 +937,7 @@ pub inline fn backendSupportsFeature(backend: std.lang.CompilerBackend, comptime
937 else => false,937 else => false,
938 },938 },
939 .is_named_enum_value => switch (backend) {939 .is_named_enum_value => switch (backend) {
940 .stage2_llvm, .stage2_x86_64 => true,940 .stage2_llvm, .stage2_x86_64, .stage2_wasm => true,
941 else => false,941 else => false,
942 },942 },
943 .error_set_has_value => switch (backend) {943 .error_set_has_value => switch (backend) {