Commit 260c845355

mlugg <mlugg@mlugg.co.uk>
2024-02-14 23:01:18
Zir: make src_node of type declarations non-optional
Previously, the `src_node` field of `struct_decl`, `union_decl`, `enum_decl`, and `opaque_decl` was optional, included in trailing data only if a flag in `Small` was set. However, this was unnecessary logic: AstGen always provided the source node. We can simplify a few bits of logic by making this field non-optional, moving it into non-trailing data. There was one place where the field was actually omitted before: the root struct of a file was at source node 0, so the node was coincidentally elided. Therefore, this commit has a fixed cost of 4 bytes of ZIR per file.
1 parent 10784c7
src/AstGen.zig
@@ -12918,20 +12918,20 @@ const GenZir = struct {
         const astgen = gz.astgen;
         const gpa = astgen.gpa;
 
+        // Node 0 is valid for the root `struct_decl` of a file!
+        assert(args.src_node != 0 or gz.parent.tag == .top);
+
         const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
 
-        try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.StructDecl).Struct.fields.len + 6);
+        try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.StructDecl).Struct.fields.len + 4);
         const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.StructDecl{
             .fields_hash_0 = fields_hash_arr[0],
             .fields_hash_1 = fields_hash_arr[1],
             .fields_hash_2 = fields_hash_arr[2],
             .fields_hash_3 = fields_hash_arr[3],
+            .src_node = gz.nodeIndexToRelative(args.src_node),
         });
 
-        if (args.src_node != 0) {
-            const node_offset = gz.nodeIndexToRelative(args.src_node);
-            astgen.extra.appendAssumeCapacity(@bitCast(node_offset));
-        }
         if (args.fields_len != 0) {
             astgen.extra.appendAssumeCapacity(args.fields_len);
         }
@@ -12949,7 +12949,6 @@ const GenZir = struct {
             .data = .{ .extended = .{
                 .opcode = .struct_decl,
                 .small = @bitCast(Zir.Inst.StructDecl.Small{
-                    .has_src_node = args.src_node != 0,
                     .has_fields_len = args.fields_len != 0,
                     .has_decls_len = args.decls_len != 0,
                     .has_backing_int = args.backing_int_ref != .none,
@@ -12981,20 +12980,19 @@ const GenZir = struct {
         const astgen = gz.astgen;
         const gpa = astgen.gpa;
 
+        assert(args.src_node != 0);
+
         const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
 
-        try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.UnionDecl).Struct.fields.len + 5);
+        try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.UnionDecl).Struct.fields.len + 4);
         const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.UnionDecl{
             .fields_hash_0 = fields_hash_arr[0],
             .fields_hash_1 = fields_hash_arr[1],
             .fields_hash_2 = fields_hash_arr[2],
             .fields_hash_3 = fields_hash_arr[3],
+            .src_node = gz.nodeIndexToRelative(args.src_node),
         });
 
-        if (args.src_node != 0) {
-            const node_offset = gz.nodeIndexToRelative(args.src_node);
-            astgen.extra.appendAssumeCapacity(@bitCast(node_offset));
-        }
         if (args.tag_type != .none) {
             astgen.extra.appendAssumeCapacity(@intFromEnum(args.tag_type));
         }
@@ -13012,7 +13010,6 @@ const GenZir = struct {
             .data = .{ .extended = .{
                 .opcode = .union_decl,
                 .small = @bitCast(Zir.Inst.UnionDecl.Small{
-                    .has_src_node = args.src_node != 0,
                     .has_tag_type = args.tag_type != .none,
                     .has_body_len = args.body_len != 0,
                     .has_fields_len = args.fields_len != 0,
@@ -13039,20 +13036,19 @@ const GenZir = struct {
         const astgen = gz.astgen;
         const gpa = astgen.gpa;
 
+        assert(args.src_node != 0);
+
         const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
 
-        try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.EnumDecl).Struct.fields.len + 5);
+        try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.EnumDecl).Struct.fields.len + 4);
         const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.EnumDecl{
             .fields_hash_0 = fields_hash_arr[0],
             .fields_hash_1 = fields_hash_arr[1],
             .fields_hash_2 = fields_hash_arr[2],
             .fields_hash_3 = fields_hash_arr[3],
+            .src_node = gz.nodeIndexToRelative(args.src_node),
         });
 
-        if (args.src_node != 0) {
-            const node_offset = gz.nodeIndexToRelative(args.src_node);
-            astgen.extra.appendAssumeCapacity(@bitCast(node_offset));
-        }
         if (args.tag_type != .none) {
             astgen.extra.appendAssumeCapacity(@intFromEnum(args.tag_type));
         }
@@ -13070,7 +13066,6 @@ const GenZir = struct {
             .data = .{ .extended = .{
                 .opcode = .enum_decl,
                 .small = @bitCast(Zir.Inst.EnumDecl.Small{
-                    .has_src_node = args.src_node != 0,
                     .has_tag_type = args.tag_type != .none,
                     .has_body_len = args.body_len != 0,
                     .has_fields_len = args.fields_len != 0,
@@ -13090,13 +13085,13 @@ const GenZir = struct {
         const astgen = gz.astgen;
         const gpa = astgen.gpa;
 
-        try astgen.extra.ensureUnusedCapacity(gpa, 2);
-        const payload_index: u32 = @intCast(astgen.extra.items.len);
+        assert(args.src_node != 0);
+
+        try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.OpaqueDecl).Struct.fields.len + 1);
+        const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.OpaqueDecl{
+            .src_node = gz.nodeIndexToRelative(args.src_node),
+        });
 
-        if (args.src_node != 0) {
-            const node_offset = gz.nodeIndexToRelative(args.src_node);
-            astgen.extra.appendAssumeCapacity(@bitCast(node_offset));
-        }
         if (args.decls_len != 0) {
             astgen.extra.appendAssumeCapacity(args.decls_len);
         }
@@ -13105,7 +13100,6 @@ const GenZir = struct {
             .data = .{ .extended = .{
                 .opcode = .opaque_decl,
                 .small = @bitCast(Zir.Inst.OpaqueDecl.Small{
-                    .has_src_node = args.src_node != 0,
                     .has_decls_len = args.decls_len != 0,
                     .name_strategy = gz.anon_name_strategy,
                 }),
src/Autodoc.zig
@@ -3395,19 +3395,10 @@ fn walkInstruction(
                         .enclosing_type = type_slot_index,
                     };
 
-                    const small = @as(Zir.Inst.OpaqueDecl.Small, @bitCast(extended.small));
-                    var extra_index: usize = extended.operand;
-
-                    const src_node: ?i32 = if (small.has_src_node) blk: {
-                        const src_node = @as(i32, @bitCast(file.zir.extra[extra_index]));
-                        extra_index += 1;
-                        break :blk src_node;
-                    } else null;
+                    const extra = file.zir.extraData(Zir.Inst.OpaqueDecl, extended.operand);
+                    var extra_index: usize = extra.end;
 
-                    const src_info = if (src_node) |sn|
-                        try self.srcLocInfo(file, sn, parent_src)
-                    else
-                        parent_src;
+                    const src_info = try self.srcLocInfo(file, extra.data.src_node, parent_src);
 
                     var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
                     var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
@@ -3498,18 +3489,10 @@ fn walkInstruction(
                     };
 
                     const small = @as(Zir.Inst.UnionDecl.Small, @bitCast(extended.small));
-                    var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.UnionDecl).Struct.fields.len;
-
-                    const src_node: ?i32 = if (small.has_src_node) blk: {
-                        const src_node = @as(i32, @bitCast(file.zir.extra[extra_index]));
-                        extra_index += 1;
-                        break :blk src_node;
-                    } else null;
+                    const extra = file.zir.extraData(Zir.Inst.UnionDecl, extended.operand);
+                    var extra_index: usize = extra.end;
 
-                    const src_info = if (src_node) |sn|
-                        try self.srcLocInfo(file, sn, parent_src)
-                    else
-                        parent_src;
+                    const src_info = try self.srcLocInfo(file, extra.data.src_node, parent_src);
 
                     // We delay analysis because union tags can refer to
                     // decls defined inside the union itself.
@@ -3628,18 +3611,10 @@ fn walkInstruction(
                     };
 
                     const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small));
-                    var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.EnumDecl).Struct.fields.len;
-
-                    const src_node: ?i32 = if (small.has_src_node) blk: {
-                        const src_node = @as(i32, @bitCast(file.zir.extra[extra_index]));
-                        extra_index += 1;
-                        break :blk src_node;
-                    } else null;
+                    const extra = file.zir.extraData(Zir.Inst.EnumDecl, extended.operand);
+                    var extra_index: usize = extra.end;
 
-                    const src_info = if (src_node) |sn|
-                        try self.srcLocInfo(file, sn, parent_src)
-                    else
-                        parent_src;
+                    const src_info = try self.srcLocInfo(file, extra.data.src_node, parent_src);
 
                     const tag_type: ?DocData.Expr = if (small.has_tag_type) blk: {
                         const tag_type = file.zir.extra[extra_index];
@@ -3779,18 +3754,10 @@ fn walkInstruction(
                     };
 
                     const small = @as(Zir.Inst.StructDecl.Small, @bitCast(extended.small));
-                    var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
-
-                    const src_node: ?i32 = if (small.has_src_node) blk: {
-                        const src_node = @as(i32, @bitCast(file.zir.extra[extra_index]));
-                        extra_index += 1;
-                        break :blk src_node;
-                    } else null;
+                    const extra = file.zir.extraData(Zir.Inst.StructDecl, extended.operand);
+                    var extra_index: usize = extra.end;
 
-                    const src_info = if (src_node) |sn|
-                        try self.srcLocInfo(file, sn, parent_src)
-                    else
-                        parent_src;
+                    const src_info = try self.srcLocInfo(file, extra.data.src_node, parent_src);
 
                     const fields_len = if (small.has_fields_len) blk: {
                         const fields_len = file.zir.extra[extra_index];
src/print_zir.zig
@@ -1405,12 +1405,6 @@ const Writer = struct {
 
         var extra_index: usize = extra.end;
 
-        const src_node: ?i32 = if (small.has_src_node) blk: {
-            const src_node = @as(i32, @bitCast(self.code.extra[extra_index]));
-            extra_index += 1;
-            break :blk src_node;
-        } else null;
-
         const fields_len = if (small.has_fields_len) blk: {
             const fields_len = self.code.extra[extra_index];
             extra_index += 1;
@@ -1453,7 +1447,7 @@ const Writer = struct {
             try stream.writeAll("{}, ");
         } else {
             const prev_parent_decl_node = self.parent_decl_node;
-            if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
+            self.parent_decl_node = self.relativeToNodeIndex(extra.data.src_node);
             defer self.parent_decl_node = prev_parent_decl_node;
 
             try stream.writeAll("{\n");
@@ -1534,7 +1528,7 @@ const Writer = struct {
             }
 
             const prev_parent_decl_node = self.parent_decl_node;
-            if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
+            self.parent_decl_node = self.relativeToNodeIndex(extra.data.src_node);
             try stream.writeAll("{\n");
             self.indent += 2;
 
@@ -1587,7 +1581,7 @@ const Writer = struct {
             try stream.writeByteNTimes(' ', self.indent);
             try stream.writeAll("})");
         }
-        try self.writeSrcNode(stream, src_node);
+        try self.writeSrcNode(stream, extra.data.src_node);
     }
 
     fn writeUnionDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
@@ -1605,12 +1599,6 @@ const Writer = struct {
 
         var extra_index: usize = extra.end;
 
-        const src_node: ?i32 = if (small.has_src_node) blk: {
-            const src_node = @as(i32, @bitCast(self.code.extra[extra_index]));
-            extra_index += 1;
-            break :blk src_node;
-        } else null;
-
         const tag_type_ref = if (small.has_tag_type) blk: {
             const tag_type_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
             extra_index += 1;
@@ -1644,7 +1632,7 @@ const Writer = struct {
             try stream.writeAll("{}");
         } else {
             const prev_parent_decl_node = self.parent_decl_node;
-            if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
+            self.parent_decl_node = self.relativeToNodeIndex(extra.data.src_node);
             defer self.parent_decl_node = prev_parent_decl_node;
 
             try stream.writeAll("{\n");
@@ -1663,7 +1651,7 @@ const Writer = struct {
 
         if (fields_len == 0) {
             try stream.writeAll("})");
-            try self.writeSrcNode(stream, src_node);
+            try self.writeSrcNode(stream, extra.data.src_node);
             return;
         }
         try stream.writeAll(", ");
@@ -1672,7 +1660,7 @@ const Writer = struct {
         extra_index += body.len;
 
         const prev_parent_decl_node = self.parent_decl_node;
-        if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
+        self.parent_decl_node = self.relativeToNodeIndex(extra.data.src_node);
         try self.writeBracedDecl(stream, body);
         try stream.writeAll(", {\n");
 
@@ -1740,7 +1728,7 @@ const Writer = struct {
         self.indent -= 2;
         try stream.writeByteNTimes(' ', self.indent);
         try stream.writeAll("})");
-        try self.writeSrcNode(stream, src_node);
+        try self.writeSrcNode(stream, extra.data.src_node);
     }
 
     fn writeEnumDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
@@ -1758,12 +1746,6 @@ const Writer = struct {
 
         var extra_index: usize = extra.end;
 
-        const src_node: ?i32 = if (small.has_src_node) blk: {
-            const src_node = @as(i32, @bitCast(self.code.extra[extra_index]));
-            extra_index += 1;
-            break :blk src_node;
-        } else null;
-
         const tag_type_ref = if (small.has_tag_type) blk: {
             const tag_type_ref = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
             extra_index += 1;
@@ -1795,7 +1777,7 @@ const Writer = struct {
             try stream.writeAll("{}, ");
         } else {
             const prev_parent_decl_node = self.parent_decl_node;
-            if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
+            self.parent_decl_node = self.relativeToNodeIndex(extra.data.src_node);
             defer self.parent_decl_node = prev_parent_decl_node;
 
             try stream.writeAll("{\n");
@@ -1816,7 +1798,7 @@ const Writer = struct {
         extra_index += body.len;
 
         const prev_parent_decl_node = self.parent_decl_node;
-        if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
+        self.parent_decl_node = self.relativeToNodeIndex(extra.data.src_node);
         try self.writeBracedDecl(stream, body);
         if (fields_len == 0) {
             try stream.writeAll(", {})");
@@ -1864,7 +1846,7 @@ const Writer = struct {
             try stream.writeByteNTimes(' ', self.indent);
             try stream.writeAll("})");
         }
-        try self.writeSrcNode(stream, src_node);
+        try self.writeSrcNode(stream, extra.data.src_node);
     }
 
     fn writeOpaqueDecl(
@@ -1873,13 +1855,8 @@ const Writer = struct {
         extended: Zir.Inst.Extended.InstData,
     ) !void {
         const small = @as(Zir.Inst.OpaqueDecl.Small, @bitCast(extended.small));
-        var extra_index: usize = extended.operand;
-
-        const src_node: ?i32 = if (small.has_src_node) blk: {
-            const src_node = @as(i32, @bitCast(self.code.extra[extra_index]));
-            extra_index += 1;
-            break :blk src_node;
-        } else null;
+        const extra = self.code.extraData(Zir.Inst.OpaqueDecl, extended.operand);
+        var extra_index: usize = extra.end;
 
         const decls_len = if (small.has_decls_len) blk: {
             const decls_len = self.code.extra[extra_index];
@@ -1893,7 +1870,7 @@ const Writer = struct {
             try stream.writeAll("{})");
         } else {
             const prev_parent_decl_node = self.parent_decl_node;
-            if (src_node) |off| self.parent_decl_node = self.relativeToNodeIndex(off);
+            self.parent_decl_node = self.relativeToNodeIndex(extra.data.src_node);
             defer self.parent_decl_node = prev_parent_decl_node;
 
             try stream.writeAll("{\n");
@@ -1903,7 +1880,7 @@ const Writer = struct {
             try stream.writeByteNTimes(' ', self.indent);
             try stream.writeAll("})");
         }
-        try self.writeSrcNode(stream, src_node);
+        try self.writeSrcNode(stream, extra.data.src_node);
     }
 
     fn writeErrorSetDecl(
src/Sema.zig
@@ -2725,7 +2725,6 @@ pub fn getStructType(
     const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
 
     var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
-    extra_index += @intFromBool(small.has_src_node);
     const fields_len = if (small.has_fields_len) blk: {
         const fields_len = sema.code.extra[extra_index];
         extra_index += 1;
@@ -2778,10 +2777,7 @@ fn zirStructDecl(
     const mod = sema.mod;
     const ip = &mod.intern_pool;
     const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
-    const src: LazySrcLoc = if (small.has_src_node) blk: {
-        const node_offset: i32 = @bitCast(sema.code.extra[extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len]);
-        break :blk LazySrcLoc.nodeOffset(node_offset);
-    } else unreachable; // MLUGG TODO
+    const src = sema.code.extraData(Zir.Inst.StructDecl, extended.operand).data.src();
 
     // Because these three things each reference each other, `undefined`
     // placeholders are used before being set after the struct type gains an
@@ -2941,13 +2937,10 @@ fn zirEnumDecl(
     const mod = sema.mod;
     const gpa = sema.gpa;
     const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
-    var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.EnumDecl).Struct.fields.len;
+    const extra = sema.code.extraData(Zir.Inst.EnumDecl, extended.operand);
+    var extra_index: usize = extra.end;
 
-    const src: LazySrcLoc = if (small.has_src_node) blk: {
-        const node_offset: i32 = @bitCast(sema.code.extra[extra_index]);
-        extra_index += 1;
-        break :blk LazySrcLoc.nodeOffset(node_offset);
-    } else unreachable; // MLUGG TODO
+    const src = extra.data.src();
     const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x };
 
     const tag_type_ref = if (small.has_tag_type) blk: {
@@ -3214,13 +3207,10 @@ fn zirUnionDecl(
     const mod = sema.mod;
     const gpa = sema.gpa;
     const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
-    var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.UnionDecl).Struct.fields.len;
+    const extra = sema.code.extraData(Zir.Inst.UnionDecl, extended.operand);
+    var extra_index: usize = extra.end;
 
-    const src: LazySrcLoc = if (small.has_src_node) blk: {
-        const node_offset: i32 = @bitCast(sema.code.extra[extra_index]);
-        extra_index += 1;
-        break :blk LazySrcLoc.nodeOffset(node_offset);
-    } else unreachable; // MLUGG TODO
+    const src = extra.data.src();
 
     extra_index += @intFromBool(small.has_tag_type);
     extra_index += @intFromBool(small.has_body_len);
@@ -3323,13 +3313,10 @@ fn zirOpaqueDecl(
 
     const mod = sema.mod;
     const small: Zir.Inst.OpaqueDecl.Small = @bitCast(extended.small);
-    var extra_index: usize = extended.operand;
+    const extra = sema.code.extraData(Zir.Inst.OpaqueDecl, extended.operand);
+    var extra_index: usize = extra.end;
 
-    const src: LazySrcLoc = if (small.has_src_node) blk: {
-        const node_offset: i32 = @bitCast(sema.code.extra[extra_index]);
-        extra_index += 1;
-        break :blk LazySrcLoc.nodeOffset(node_offset);
-    } else unreachable; // MLUGG TODO
+    const src = extra.data.src();
 
     const decls_len = if (small.has_decls_len) blk: {
         const decls_len = sema.code.extra[extra_index];
@@ -35662,7 +35649,6 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp
 
     if (small.has_backing_int) {
         var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
-        extra_index += @intFromBool(small.has_src_node);
         extra_index += @intFromBool(small.has_fields_len);
         extra_index += @intFromBool(small.has_decls_len);
 
@@ -36374,8 +36360,6 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {
     const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
     var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
 
-    extra_index += @intFromBool(small.has_src_node);
-
     const fields_len = if (small.has_fields_len) blk: {
         const fields_len = zir.extra[extra_index];
         extra_index += 1;
@@ -36843,7 +36827,6 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
     var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.UnionDecl).Struct.fields.len;
 
     const src = LazySrcLoc.nodeOffset(0);
-    extra_index += @intFromBool(small.has_src_node);
 
     const tag_type_ref: Zir.Inst.Ref = if (small.has_tag_type) blk: {
         const ty_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
src/Zir.zig
@@ -3022,20 +3022,19 @@ pub const Inst = struct {
     };
 
     /// Trailing:
-    /// 0. src_node: i32, // if has_src_node
-    /// 1. fields_len: u32, // if has_fields_len
-    /// 2. decls_len: u32, // if has_decls_len
-    /// 3. backing_int_body_len: u32, // if has_backing_int
-    /// 4. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 0
-    /// 5. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 0
-    /// 6. decl: Index, // for every decls_len; points to a `declaration` instruction
-    /// 7. flags: u32 // for every 8 fields
+    /// 0. fields_len: u32, // if has_fields_len
+    /// 1. decls_len: u32, // if has_decls_len
+    /// 2. backing_int_body_len: u32, // if has_backing_int
+    /// 3. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 0
+    /// 4. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 0
+    /// 5. decl: Index, // for every decls_len; points to a `declaration` instruction
+    /// 6. flags: u32 // for every 8 fields
     ///    - sets of 4 bits:
     ///      0b000X: whether corresponding field has an align expression
     ///      0b00X0: whether corresponding field has a default expression
     ///      0b0X00: whether corresponding field is comptime
     ///      0bX000: whether corresponding field has a type expression
-    /// 8. fields: { // for every fields_len
+    /// 7. fields: { // for every fields_len
     ///        field_name: u32, // if !is_tuple
     ///        doc_comment: NullTerminatedString, // .empty if no doc comment
     ///        field_type: Ref, // if corresponding bit is not set. none means anytype.
@@ -3043,7 +3042,7 @@ pub const Inst = struct {
     ///        align_body_len: u32, // if corresponding bit is set
     ///        init_body_len: u32, // if corresponding bit is set
     ///    }
-    /// 10. bodies: { // for every fields_len
+    /// 8. bodies: { // for every fields_len
     ///        field_type_body_inst: Inst, // for each field_type_body_len
     ///        align_body_inst: Inst, // for each align_body_len
     ///        init_body_inst: Inst, // for each init_body_len
@@ -3055,8 +3054,13 @@ pub const Inst = struct {
         fields_hash_1: u32,
         fields_hash_2: u32,
         fields_hash_3: u32,
+        src_node: i32,
+
+        pub fn src(self: StructDecl) LazySrcLoc {
+            return LazySrcLoc.nodeOffset(self.src_node);
+        }
+
         pub const Small = packed struct {
-            has_src_node: bool,
             has_fields_len: bool,
             has_decls_len: bool,
             has_backing_int: bool,
@@ -3068,7 +3072,7 @@ pub const Inst = struct {
             any_default_inits: bool,
             any_comptime_fields: bool,
             any_aligned_fields: bool,
-            _: u2 = undefined,
+            _: u3 = undefined,
         };
     };
 
@@ -3102,16 +3106,15 @@ pub const Inst = struct {
     };
 
     /// Trailing:
-    /// 0. src_node: i32, // if has_src_node
-    /// 1. tag_type: Ref, // if has_tag_type
-    /// 2. body_len: u32, // if has_body_len
-    /// 3. fields_len: u32, // if has_fields_len
-    /// 4. decls_len: u32, // if has_decls_len
-    /// 5. decl: Index, // for every decls_len; points to a `declaration` instruction
-    /// 6. inst: Index // for every body_len
-    /// 7. has_bits: u32 // for every 32 fields
+    /// 0. tag_type: Ref, // if has_tag_type
+    /// 1. body_len: u32, // if has_body_len
+    /// 2. fields_len: u32, // if has_fields_len
+    /// 3. decls_len: u32, // if has_decls_len
+    /// 4. decl: Index, // for every decls_len; points to a `declaration` instruction
+    /// 5. inst: Index // for every body_len
+    /// 6. has_bits: u32 // for every 32 fields
     ///    - the bit is whether corresponding field has an value expression
-    /// 8. fields: { // for every fields_len
+    /// 7. fields: { // for every fields_len
     ///        field_name: u32,
     ///        doc_comment: u32, // .empty if no doc_comment
     ///        value: Ref, // if corresponding bit is set
@@ -3123,33 +3126,37 @@ pub const Inst = struct {
         fields_hash_1: u32,
         fields_hash_2: u32,
         fields_hash_3: u32,
+        src_node: i32,
+
+        pub fn src(self: EnumDecl) LazySrcLoc {
+            return LazySrcLoc.nodeOffset(self.src_node);
+        }
+
         pub const Small = packed struct {
-            has_src_node: bool,
             has_tag_type: bool,
             has_body_len: bool,
             has_fields_len: bool,
             has_decls_len: bool,
             name_strategy: NameStrategy,
             nonexhaustive: bool,
-            _: u8 = undefined,
+            _: u9 = undefined,
         };
     };
 
     /// Trailing:
-    /// 0. src_node: i32, // if has_src_node
-    /// 1. tag_type: Ref, // if has_tag_type
-    /// 2. body_len: u32, // if has_body_len
-    /// 3. fields_len: u32, // if has_fields_len
-    /// 4. decls_len: u32, // if has_decls_len
-    /// 5. decl: Index, // for every decls_len; points to a `declaration` instruction
-    /// 6. inst: Index // for every body_len
-    /// 7. has_bits: u32 // for every 8 fields
+    /// 0. tag_type: Ref, // if has_tag_type
+    /// 1. body_len: u32, // if has_body_len
+    /// 2. fields_len: u32, // if has_fields_len
+    /// 3. decls_len: u32, // if has_decls_len
+    /// 4. decl: Index, // for every decls_len; points to a `declaration` instruction
+    /// 5. inst: Index // for every body_len
+    /// 6. has_bits: u32 // for every 8 fields
     ///    - sets of 4 bits:
     ///      0b000X: whether corresponding field has a type expression
     ///      0b00X0: whether corresponding field has a align expression
     ///      0b0X00: whether corresponding field has a tag value expression
     ///      0bX000: unused
-    /// 8. fields: { // for every fields_len
+    /// 7. fields: { // for every fields_len
     ///        field_name: NullTerminatedString, // null terminated string index
     ///        doc_comment: NullTerminatedString, // .empty if no doc comment
     ///        field_type: Ref, // if corresponding bit is set
@@ -3164,8 +3171,13 @@ pub const Inst = struct {
         fields_hash_1: u32,
         fields_hash_2: u32,
         fields_hash_3: u32,
+        src_node: i32,
+
+        pub fn src(self: UnionDecl) LazySrcLoc {
+            return LazySrcLoc.nodeOffset(self.src_node);
+        }
+
         pub const Small = packed struct {
-            has_src_node: bool,
             has_tag_type: bool,
             has_body_len: bool,
             has_fields_len: bool,
@@ -3180,20 +3192,24 @@ pub const Inst = struct {
             ///    true      | false         |  union(T) { }
             auto_enum_tag: bool,
             any_aligned_fields: bool,
-            _: u5 = undefined,
+            _: u6 = undefined,
         };
     };
 
     /// Trailing:
-    /// 0. src_node: i32, // if has_src_node
-    /// 1. decls_len: u32, // if has_decls_len
-    /// 2. decl: Index, // for every decls_len; points to a `declaration` instruction
+    /// 0. decls_len: u32, // if has_decls_len
+    /// 1. decl: Index, // for every decls_len; points to a `declaration` instruction
     pub const OpaqueDecl = struct {
+        src_node: i32,
+
+        pub fn src(self: OpaqueDecl) LazySrcLoc {
+            return LazySrcLoc.nodeOffset(self.src_node);
+        }
+
         pub const Small = packed struct {
-            has_src_node: bool,
             has_decls_len: bool,
             name_strategy: NameStrategy,
-            _: u12 = undefined,
+            _: u13 = undefined,
         };
     };
 
@@ -3495,7 +3511,6 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
                 .struct_decl => {
                     const small: Inst.StructDecl.Small = @bitCast(extended.small);
                     var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.StructDecl).Struct.fields.len);
-                    extra_index += @intFromBool(small.has_src_node);
                     extra_index += @intFromBool(small.has_fields_len);
                     const decls_len = if (small.has_decls_len) decls_len: {
                         const decls_len = zir.extra[extra_index];
@@ -3522,7 +3537,6 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
                 .enum_decl => {
                     const small: Inst.EnumDecl.Small = @bitCast(extended.small);
                     var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.EnumDecl).Struct.fields.len);
-                    extra_index += @intFromBool(small.has_src_node);
                     extra_index += @intFromBool(small.has_tag_type);
                     extra_index += @intFromBool(small.has_body_len);
                     extra_index += @intFromBool(small.has_fields_len);
@@ -3541,7 +3555,6 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
                 .union_decl => {
                     const small: Inst.UnionDecl.Small = @bitCast(extended.small);
                     var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.UnionDecl).Struct.fields.len);
-                    extra_index += @intFromBool(small.has_src_node);
                     extra_index += @intFromBool(small.has_tag_type);
                     extra_index += @intFromBool(small.has_body_len);
                     extra_index += @intFromBool(small.has_fields_len);
@@ -3559,8 +3572,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
                 },
                 .opaque_decl => {
                     const small: Inst.OpaqueDecl.Small = @bitCast(extended.small);
-                    var extra_index: u32 = extended.operand;
-                    extra_index += @intFromBool(small.has_src_node);
+                    var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.OpaqueDecl).Struct.fields.len);
                     const decls_len = if (small.has_decls_len) decls_len: {
                         const decls_len = zir.extra[extra_index];
                         extra_index += 1;