authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2026-06-09 21:14:36+03:30
committergravatar for alichraghi@noreply.codeberg.orgAli Cheraghi <alichraghi@noreply.codeberg.org> 2026-06-14 09:11:59+02:00
log88d2961df475806a73af0f2eb4e4076159dc7f61
tree1e1d474a5c1c2f2c0a75cda00b9cd22a49e96bb5
parent281991328ed25c049c1b86b21fd72815cb0959d8

spirv: codegen and linker fixes for logical-addressing

A handful of changes to get the regressed behavior tests running again. - Replace `decorateBlockOffsets` with a recursive function `decorateLayout` that walks arrays, vectors, structs, unions, optionals, and error unions, emitting `ArrayStride` and member `Offset` decorations at every level. Previously we weren't handling nested types. - Restrict `Block` decoration to struct types with `uniform`, `push_constant`, `storage_buffer` storage classes. Previously we decorated through every pointer, contaminating the cached struct type so the same shape used as a stack local also picked up `Block`. - Lower `ptr_slice_ptr_ptr` and `ptr_slice_len_ptr` - No longer emit a redundant `**T` typed `OpVariable` for function parameters. Logical addressing also forbids such variables. - Eliminate dead code from invocation globals unreachable from any entry point. Reverting the workaround in `lib/std/start.zig`.

3 files changed, 157 insertions(+), 45 deletions(-)

lib/std/start.zig+2-4
...@@ -19,9 +19,7 @@ comptime {...@@ -19,9 +19,7 @@ comptime {
19 // decls there get run.19 // decls there get run.
20 _ = root;20 _ = root;
2121
22 if (builtin.zig_backend == .stage2_spirv) {22 if (builtin.output_mode == .Lib and builtin.link_mode == .dynamic) {
23 // Do nothing
24 } else if (builtin.output_mode == .Lib and builtin.link_mode == .dynamic) {
25 const dll_main_crt_startup = if (builtin.abi.isGnu()) "DllMainCRTStartup" else "_DllMainCRTStartup";23 const dll_main_crt_startup = if (builtin.abi.isGnu()) "DllMainCRTStartup" else "_DllMainCRTStartup";
26 if (native_os == .windows and !builtin.link_libc and !@hasDecl(root, dll_main_crt_startup)) {24 if (native_os == .windows and !builtin.link_libc and !@hasDecl(root, dll_main_crt_startup)) {
27 @export(&DllMainCRTStartup, .{ .name = dll_main_crt_startup });25 @export(&DllMainCRTStartup, .{ .name = dll_main_crt_startup });
...@@ -72,7 +70,7 @@ comptime {...@@ -72,7 +70,7 @@ comptime {
72 // case it's not required to provide an entrypoint such as main.70 // case it's not required to provide an entrypoint such as main.
73 if (!@hasDecl(root, start_sym_name) and @hasDecl(root, "main")) @export(&wasm_freestanding_start, .{ .name = start_sym_name });71 if (!@hasDecl(root, start_sym_name) and @hasDecl(root, "main")) @export(&wasm_freestanding_start, .{ .name = start_sym_name });
74 } else switch (native_os) {72 } else switch (native_os) {
75 .other, .freestanding, .@"3ds", .psp, .vita => {},73 .other, .freestanding, .@"3ds", .psp, .vita, .vulkan, .opengl, .opencl => {},
76 else => if (!@hasDecl(root, start_sym_name)) @export(&_start, .{ .name = start_sym_name }),74 else => if (!@hasDecl(root, start_sym_name)) @export(&_start, .{ .name = start_sym_name }),
77 }75 }
78 }76 }
src/codegen/spirv/CodeGen.zig+119-41
...@@ -152,6 +152,7 @@ base_line: u32,...@@ -152,6 +152,7 @@ base_line: u32,
152block_label: Id = .none,152block_label: Id = .none,
153next_arg_index: u32 = 0,153next_arg_index: u32 = 0,
154args: std.ArrayList(Id) = .empty,154args: std.ArrayList(Id) = .empty,
155virtual_allocas: std.AutoHashMapUnmanaged(Id, ?Id) = .empty,
155inst_results: std.AutoHashMapUnmanaged(Air.Inst.Index, Id) = .empty,156inst_results: std.AutoHashMapUnmanaged(Air.Inst.Index, Id) = .empty,
156id_scratch: std.ArrayList(Id) = .empty,157id_scratch: std.ArrayList(Id) = .empty,
157prologue: Section = .{},158prologue: Section = .{},
...@@ -161,6 +162,7 @@ pub fn deinit(cg: *CodeGen) void {...@@ -161,6 +162,7 @@ pub fn deinit(cg: *CodeGen) void {
161 const gpa = cg.module.gpa;162 const gpa = cg.module.gpa;
162 cg.control_flow.deinit(gpa);163 cg.control_flow.deinit(gpa);
163 cg.args.deinit(gpa);164 cg.args.deinit(gpa);
165 cg.virtual_allocas.deinit(gpa);
164 cg.inst_results.deinit(gpa);166 cg.inst_results.deinit(gpa);
165 cg.id_scratch.deinit(gpa);167 cg.id_scratch.deinit(gpa);
166 cg.prologue.deinit(gpa);168 cg.prologue.deinit(gpa);
...@@ -269,23 +271,19 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -269,23 +271,19 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
269271
270 switch (target.os.tag) {272 switch (target.os.tag) {
271 .vulkan, .opengl => {273 .vulkan, .opengl => {
272 if (ty.zigTypeTag(zcu) == .@"struct") {274 switch (storage_class) {
273 switch (storage_class) {275 .uniform, .push_constant, .storage_buffer, .physical_storage_buffer => {
274 .uniform,276 if (ty.zigTypeTag(zcu) == .@"struct" and storage_class != .physical_storage_buffer) {
275 .push_constant,
276 .storage_buffer,
277 => {
278 try cg.module.decorate(ty_id, .block);277 try cg.module.decorate(ty_id, .block);
279 try cg.decorateBlockOffsets(ty, ty_id);278 }
280 },279 try cg.module.decorate(ptr_ty_id, .{
281 else => {},280 .array_stride = .{ .array_stride = @intCast(ty.abiSize(zcu)) },
282 }281 });
282 try cg.decorateLayout(ty, ty_id);
283 },
284 else => {},
283 }285 }
284286
285 try cg.module.decorate(ptr_ty_id, .{
286 .array_stride = .{ .array_stride = @intCast(ty.abiSize(zcu)) },
287 });
288
289 if (key.decoration) |decoration| switch (decoration) {287 if (key.decoration) |decoration| switch (decoration) {
290 .location => |location| {288 .location => |location| {
291 if (storage_class != .output and storage_class != .input and storage_class != .uniform_constant) {289 if (storage_class != .output and storage_class != .input and storage_class != .uniform_constant) {
...@@ -378,18 +376,82 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {...@@ -378,18 +376,82 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void {
378 cg.module.declPtr(spv_decl_index).end_dep = cg.module.decl_deps.items.len;376 cg.module.declPtr(spv_decl_index).end_dep = cg.module.decl_deps.items.len;
379}377}
380378
381fn decorateBlockOffsets(cg: *CodeGen, ty: Type, ty_id: spec.Id) !void {379fn decorateLayout(cg: *CodeGen, ty: Type, ty_id: spec.Id) Error!void {
382 const zcu = cg.module.zcu;380 const zcu = cg.module.zcu;
383 const ip = &zcu.intern_pool;381 const ip = &zcu.intern_pool;
384 const struct_type = ip.loadStructType(ty.toIntern());382 switch (ty.zigTypeTag(zcu)) {
385 var it = struct_type.iterateRuntimeOrder(ip);383 .array => {
386 var member: u32 = 0;384 const elem_ty = ty.childType(zcu);
387 while (it.next()) |field_index| {385 if (!elem_ty.hasRuntimeBits(zcu)) return;
388 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);386 try cg.module.decorate(ty_id, .{
389 if (!field_ty.hasRuntimeBits(zcu)) continue;387 .array_stride = .{ .array_stride = @intCast(elem_ty.abiSize(zcu)) },
390 const offset: u32 = @intCast(ty.structFieldOffset(field_index, zcu));388 });
391 try cg.module.decorateMember(ty_id, member, .{ .offset = .{ .byte_offset = offset } });389 try cg.decorateLayout(elem_ty, try cg.resolveType(elem_ty, .indirect));
392 member += 1;390 },
391 .vector => {
392 const elem_ty = ty.childType(zcu);
393 try cg.decorateLayout(elem_ty, try cg.resolveType(elem_ty, .indirect));
394 if (cg.isSpvVector(ty)) return;
395 try cg.module.decorate(ty_id, .{
396 .array_stride = .{ .array_stride = @intCast(elem_ty.abiSize(zcu)) },
397 });
398 },
399 .@"struct" => switch (ip.indexToKey(ty.toIntern())) {
400 .struct_type => {
401 const struct_type = ip.loadStructType(ty.toIntern());
402 if (struct_type.layout == .@"packed") return;
403 var it = struct_type.iterateRuntimeOrder(ip);
404 var member: u32 = 0;
405 while (it.next()) |field_index| {
406 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
407 if (!field_ty.hasRuntimeBits(zcu)) continue;
408 const offset: u32 = @intCast(ty.structFieldOffset(field_index, zcu));
409 try cg.module.decorateMember(ty_id, member, .{ .offset = .{ .byte_offset = offset } });
410 try cg.decorateLayout(field_ty, try cg.resolveType(field_ty, .indirect));
411 member += 1;
412 }
413 },
414 .tuple_type => |tuple| {
415 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, field_val| {
416 if (field_val != .none) continue;
417 const ft: Type = .fromInterned(field_ty);
418 if (ft.hasRuntimeBits(zcu)) try cg.decorateLayout(ft, try cg.resolveType(ft, .indirect));
419 }
420 },
421 else => {},
422 },
423 .@"union" => {
424 const union_obj = zcu.typeToUnion(ty).?;
425 if (union_obj.layout == .@"packed") return;
426 const layout = cg.unionLayout(ty);
427 if (layout.tag_size != 0) {
428 const tag_ty: Type = .fromInterned(union_obj.enum_tag_type);
429 try cg.decorateLayout(tag_ty, try cg.resolveType(tag_ty, .indirect));
430 }
431 if (layout.has_payload) {
432 try cg.decorateLayout(layout.payload_ty, try cg.resolveType(layout.payload_ty, .indirect));
433 }
434 const u8_id = try cg.resolveType(.u8, .direct);
435 if (layout.payload_padding_size != 0) {
436 const len_id = try cg.constInt(.u32, layout.payload_padding_size);
437 const arr_id = try cg.module.arrayType(len_id, u8_id);
438 try cg.module.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } });
439 }
440 if (layout.padding_size != 0) {
441 const len_id = try cg.constInt(.u32, layout.padding_size);
442 const arr_id = try cg.module.arrayType(len_id, u8_id);
443 try cg.module.decorate(arr_id, .{ .array_stride = .{ .array_stride = 1 } });
444 }
445 },
446 .optional => {
447 const payload_ty = ty.optionalChild(zcu);
448 if (payload_ty.hasRuntimeBits(zcu)) try cg.decorateLayout(payload_ty, try cg.resolveType(payload_ty, .indirect));
449 },
450 .error_union => {
451 const payload_ty = ty.errorUnionPayload(zcu);
452 if (payload_ty.hasRuntimeBits(zcu)) try cg.decorateLayout(payload_ty, try cg.resolveType(payload_ty, .indirect));
453 },
454 else => {},
393 }455 }
394}456}
395457
...@@ -1408,18 +1470,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {...@@ -1408,18 +1470,7 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id {
1408 return try cg.module.arrayType(len_id, elem_ty_id);1470 return try cg.module.arrayType(len_id, elem_ty_id);
1409 } else {1471 } else {
1410 const total_len_id = try cg.constInt(.u32, total_len);1472 const total_len_id = try cg.constInt(.u32, total_len);
1411 const result_id = try cg.module.arrayType(total_len_id, elem_ty_id);1473 return try cg.module.arrayType(total_len_id, elem_ty_id);
1412 switch (target.os.tag) {
1413 .vulkan, .opengl => {
1414 try cg.module.decorate(result_id, .{
1415 .array_stride = .{
1416 .array_stride = @intCast(elem_ty.abiSize(zcu)),
1417 },
1418 });
1419 },
1420 else => {},
1421 }
1422 return result_id;
1423 }1474 }
1424 },1475 },
1425 .vector => {1476 .vector => {
...@@ -2518,11 +2569,12 @@ fn generateTestEntryPoint(...@@ -2518,11 +2569,12 @@ fn generateTestEntryPoint(
2518 const spv_err_decl_index = try cg.module.allocDecl(.global);2569 const spv_err_decl_index = try cg.module.allocDecl(.global);
2519 const err_buf_result_id = cg.module.declPtr(spv_err_decl_index).result_id;2570 const err_buf_result_id = cg.module.declPtr(spv_err_decl_index).result_id;
25202571
2521 const buffer_struct_ty_id = try cg.module.structType(2572 const buffer_struct_ty_id = cg.module.allocId();
2522 &.{anyerror_ty_id},2573 try cg.module.sections.globals.emit(gpa, .OpTypeStruct, .{
2523 &.{"error_out"},2574 .id_result = buffer_struct_ty_id,
2524 .none,2575 .id_ref = &.{anyerror_ty_id},
2525 );2576 });
2577 try cg.module.memberDebugName(buffer_struct_ty_id, 0, "error_out");
2526 try cg.module.decorate(buffer_struct_ty_id, .block);2578 try cg.module.decorate(buffer_struct_ty_id, .block);
2527 try cg.module.decorateMember(buffer_struct_ty_id, 0, .{ .offset = .{ .byte_offset = 0 } });2579 try cg.module.decorateMember(buffer_struct_ty_id, 0, .{ .offset = .{ .byte_offset = 0 } });
25282580
...@@ -2794,6 +2846,8 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void {...@@ -2794,6 +2846,8 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void {
27942846
2795 .slice_ptr => try cg.airSliceField(inst, 0),2847 .slice_ptr => try cg.airSliceField(inst, 0),
2796 .slice_len => try cg.airSliceField(inst, 1),2848 .slice_len => try cg.airSliceField(inst, 1),
2849 .ptr_slice_ptr_ptr => try cg.airStructFieldPtrIndex(inst, 0),
2850 .ptr_slice_len_ptr => try cg.airStructFieldPtrIndex(inst, 1),
2797 .spirv_runtime_array_len => try cg.airSpirvRuntimeArrayLen(inst),2851 .spirv_runtime_array_len => try cg.airSpirvRuntimeArrayLen(inst),
2798 .slice_elem_ptr => try cg.airSliceElemPtr(inst),2852 .slice_elem_ptr => try cg.airSliceElemPtr(inst),
2799 .slice_elem_val => try cg.airSliceElemVal(inst),2853 .slice_elem_val => try cg.airSliceElemVal(inst),
...@@ -4052,6 +4106,7 @@ fn airBitCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4052,6 +4106,7 @@ fn airBitCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4052 return try result.materialize(cg);4106 return try result.materialize(cg);
4053 }4107 }
4054 const operand_id = try cg.resolve(ty_op.operand);4108 const operand_id = try cg.resolve(ty_op.operand);
4109 if (cg.virtual_allocas.contains(operand_id)) return operand_id;
4055 return try cg.bitCast(result_ty, operand_ty, operand_id);4110 return try cg.bitCast(result_ty, operand_ty, operand_id);
4056}4111}
40574112
...@@ -4881,6 +4936,21 @@ fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4881,6 +4936,21 @@ fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4881 const target = zcu.getTarget();4936 const target = zcu.getTarget();
4882 const ptr_ty = cg.typeOfIndex(inst);4937 const ptr_ty = cg.typeOfIndex(inst);
4883 const child_ty = ptr_ty.childType(zcu);4938 const child_ty = ptr_ty.childType(zcu);
4939
4940 switch (target.os.tag) {
4941 .vulkan, .opengl => {
4942 if (child_ty.zigTypeTag(zcu) == .pointer and !child_ty.isSlice(zcu)) {
4943 const as = child_ty.ptrAddressSpace(zcu);
4944 if (cg.module.storageClass(as) == .function) {
4945 const result_id = cg.module.allocId();
4946 try cg.virtual_allocas.put(cg.module.gpa, result_id, null);
4947 return result_id;
4948 }
4949 }
4950 },
4951 else => {},
4952 }
4953
4884 const child_ty_id = try cg.resolveType(child_ty, .indirect);4954 const child_ty_id = try cg.resolveType(child_ty, .indirect);
4885 const ptr_align = ptr_ty.ptrAlignment(zcu);4955 const ptr_align = ptr_ty.ptrAlignment(zcu);
4886 const result_id = try cg.alloc(child_ty_id, null);4956 const result_id = try cg.alloc(child_ty_id, null);
...@@ -5355,6 +5425,8 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5355,6 +5425,8 @@ fn airLoad(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5355 const operand = try cg.resolve(ty_op.operand);5425 const operand = try cg.resolve(ty_op.operand);
5356 if (!ptr_ty.isVolatilePtr(zcu) and cg.liveness.isUnused(inst)) return null;5426 if (!ptr_ty.isVolatilePtr(zcu) and cg.liveness.isUnused(inst)) return null;
53575427
5428 if (cg.virtual_allocas.get(operand)) |stored| return stored.?;
5429
5358 return try cg.load(elem_ty, operand, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) });5430 return try cg.load(elem_ty, operand, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) });
5359}5431}
53605432
...@@ -5366,6 +5438,11 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {...@@ -5366,6 +5438,11 @@ fn airStore(cg: *CodeGen, inst: Air.Inst.Index) !void {
5366 const ptr = try cg.resolve(bin_op.lhs);5438 const ptr = try cg.resolve(bin_op.lhs);
5367 const value = try cg.resolve(bin_op.rhs);5439 const value = try cg.resolve(bin_op.rhs);
53685440
5441 if (cg.virtual_allocas.getPtr(ptr)) |slot| {
5442 slot.* = value;
5443 return;
5444 }
5445
5369 try cg.store(elem_ty, ptr, value, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) });5446 try cg.store(elem_ty, ptr, value, .{ .is_volatile = ptr_ty.isVolatilePtr(zcu) });
5370}5447}
53715448
...@@ -5933,6 +6010,7 @@ fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -5933,6 +6010,7 @@ fn airDbgInlineBlock(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
5933fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void {6010fn airDbgVar(cg: *CodeGen, inst: Air.Inst.Index) !void {
5934 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;6011 const pl_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
5935 const target_id = try cg.resolve(pl_op.operand);6012 const target_id = try cg.resolve(pl_op.operand);
6013 if (cg.virtual_allocas.contains(target_id)) return;
5936 const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);6014 const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
5937 try cg.module.debugName(target_id, name.toSlice(cg.air));6015 try cg.module.debugName(target_id, name.toSlice(cg.air));
5938}6016}
src/link/SpirV/lower_invocation_globals.zig+36
...@@ -46,6 +46,11 @@ const ModuleInfo = struct {...@@ -46,6 +46,11 @@ const ModuleInfo = struct {
46 callee_store: []const ResultId,46 callee_store: []const ResultId,
47 /// Maps each invocation global result-id to a type-id.47 /// Maps each invocation global result-id to a type-id.
48 invocation_globals: std.array_hash_map.Auto(ResultId, InvocationGlobal),48 invocation_globals: std.array_hash_map.Auto(ResultId, InvocationGlobal),
49 /// Subset of `invocation_globals` reachable from any entry point.
50 live_invocation_globals: std.array_hash_map.Auto(ResultId, void),
51 /// Initializer functions of unreachable invocation globals. Their
52 /// OpFunction...OpFunctionEnd ranges are skipped during rewriteFunctions.
53 dead_initializers: std.array_hash_map.Auto(ResultId, void),
4954
50 /// Fetch the list of callees per function. Guaranteed to contain only unique IDs.55 /// Fetch the list of callees per function. Guaranteed to contain only unique IDs.
51 fn callees(self: ModuleInfo, fn_id: ResultId) []const ResultId {56 fn callees(self: ModuleInfo, fn_id: ResultId) []const ResultId {
...@@ -196,6 +201,8 @@ const ModuleInfo = struct {...@@ -196,6 +201,8 @@ const ModuleInfo = struct {
196 .entry_points = entry_points,201 .entry_points = entry_points,
197 .callee_store = callee_store.items,202 .callee_store = callee_store.items,
198 .invocation_globals = invocation_globals,203 .invocation_globals = invocation_globals,
204 .live_invocation_globals = .empty,
205 .dead_initializers = .empty,
199 };206 };
200 }207 }
201208
...@@ -203,6 +210,25 @@ const ModuleInfo = struct {...@@ -203,6 +210,25 @@ const ModuleInfo = struct {
203 fn resolve(self: *ModuleInfo, arena: Allocator) !void {210 fn resolve(self: *ModuleInfo, arena: Allocator) !void {
204 try self.resolveInvocationGlobalUsage(arena);211 try self.resolveInvocationGlobalUsage(arena);
205 try self.resolveInvocationGlobalDependencies(arena);212 try self.resolveInvocationGlobalDependencies(arena);
213 try self.resolveLiveSet(arena);
214 }
215
216 fn resolveLiveSet(self: *ModuleInfo, arena: Allocator) !void {
217 for (self.entry_points.keys()) |ep_id| {
218 const ep_info = self.functions.get(ep_id) orelse continue;
219 for (ep_info.invocation_globals.keys()) |g| {
220 try self.live_invocation_globals.put(arena, g, {});
221 const g_info = self.invocation_globals.get(g).?;
222 for (g_info.dependencies.keys()) |dep| {
223 try self.live_invocation_globals.put(arena, dep, {});
224 }
225 }
226 }
227 for (self.invocation_globals.keys(), self.invocation_globals.values()) |g, info| {
228 if (info.initializer == .none) continue;
229 if (self.live_invocation_globals.contains(g)) continue;
230 try self.dead_initializers.put(arena, info.initializer, {});
231 }
206 }232 }
207233
208 /// For each function, extend the list of `invocation_globals` with the234 /// For each function, extend the list of `invocation_globals` with the
...@@ -385,6 +411,7 @@ const ModuleBuilder = struct {...@@ -385,6 +411,7 @@ const ModuleBuilder = struct {
385 .OpName => {411 .OpName => {
386 const id: ResultId = @enumFromInt(inst.operands[0]);412 const id: ResultId = @enumFromInt(inst.operands[0]);
387 if (info.invocation_globals.contains(id)) continue;413 if (info.invocation_globals.contains(id)) continue;
414 if (info.dead_initializers.contains(id)) continue;
388 },415 },
389 .OpExtInstImport => {416 .OpExtInstImport => {
390 const set_id: ResultId = @enumFromInt(inst.operands[0]);417 const set_id: ResultId = @enumFromInt(inst.operands[0]);
...@@ -502,9 +529,14 @@ const ModuleBuilder = struct {...@@ -502,9 +529,14 @@ const ModuleBuilder = struct {
502 var operands = std.array_list.Managed(u32).init(self.arena);529 var operands = std.array_list.Managed(u32).init(self.arena);
503530
504 var maybe_current_function: ?ResultId = null;531 var maybe_current_function: ?ResultId = null;
532 var skip_until_end: bool = false;
505 var it = binary.iterateInstructionsFrom(binary.sections.functions);533 var it = binary.iterateInstructionsFrom(binary.sections.functions);
506 self.new_functions_section = self.section.instructions.items.len;534 self.new_functions_section = self.section.instructions.items.len;
507 while (it.next()) |inst| {535 while (it.next()) |inst| {
536 if (skip_until_end) {
537 if (inst.opcode == .OpFunctionEnd) skip_until_end = false;
538 continue;
539 }
508 result_id_offsets.items.len = 0;540 result_id_offsets.items.len = 0;
509 try parser.parseInstructionResultIds(binary, inst, &result_id_offsets);541 try parser.parseInstructionResultIds(binary, inst, &result_id_offsets);
510542
...@@ -527,6 +559,10 @@ const ModuleBuilder = struct {...@@ -527,6 +559,10 @@ const ModuleBuilder = struct {
527 .OpFunction => {559 .OpFunction => {
528 // Re-declare the function with the new parameters.560 // Re-declare the function with the new parameters.
529 const func: ResultId = @enumFromInt(operands.items[1]);561 const func: ResultId = @enumFromInt(operands.items[1]);
562 if (info.dead_initializers.contains(func)) {
563 skip_until_end = true;
564 continue;
565 }
530 const fn_info = info.functions.get(func).?;566 const fn_info = info.functions.get(func).?;
531 const new_info = self.function_new_info.get(func).?;567 const new_info = self.function_new_info.get(func).?;
532568