Commit b039a8b615

mlugg <mlugg@mlugg.co.uk>
2025-01-05 01:50:58
compiler: slightly simplify builtin decl memoization
Rather than `Zcu.BuiltinDecl.Memoized` being a struct with fields, it can instead just be an array, indexed by the enum. This allows runtime indexing, avoiding a few now-unnecessary `inline` switch cases.
1 parent 136c5a9
Changed files (4)
src/codegen/llvm.zig
@@ -5754,9 +5754,7 @@ pub const FuncGen = struct {
         const o = fg.ng.object;
         const zcu = o.pt.zcu;
         const ip = &zcu.intern_pool;
-        const panic_msg_val: InternPool.Index = switch (panic_id) {
-            inline else => |ct_panic_id| @field(zcu.builtin_decl_values, "Panic.messages." ++ @tagName(ct_panic_id)),
-        };
+        const panic_msg_val = zcu.builtin_decl_values.get(panic_id.toBuiltin());
         assert(panic_msg_val != .none);
         const msg_len = Value.fromInterned(panic_msg_val).typeOf(zcu).childType(zcu).arrayLen(zcu);
         const msg_ptr = try o.lowerValue(panic_msg_val);
@@ -5770,7 +5768,7 @@ pub const FuncGen = struct {
         //   ptr null,                                               ; stack trace
         //   ptr @2,                                                 ; addr (null ?usize)
         // )
-        const panic_func = zcu.funcInfo(zcu.builtin_decl_values.@"Panic.call");
+        const panic_func = zcu.funcInfo(zcu.builtin_decl_values.get(.@"Panic.call"));
         const panic_nav = ip.getNav(panic_func.owner_nav);
         const fn_info = zcu.typeToFunc(Type.fromInterned(panic_nav.typeOf(ip))).?;
         const panic_global = try o.resolveLlvmFunction(panic_func.owner_nav);
src/Zcu/PerThread.zig
@@ -590,13 +590,13 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized
         _ = zcu.transitive_failed_analysis.swapRemove(unit);
     } else {
         if (prev_failed) return error.AnalysisFail;
-        // We use an arbitrary field to check if the state has been resolved yet.
-        const val = switch (stage) {
-            .main => zcu.builtin_decl_values.Type,
-            .panic => zcu.builtin_decl_values.Panic,
-            .va_list => zcu.builtin_decl_values.VaList,
+        // We use an arbitrary element to check if the state has been resolved yet.
+        const to_check: Zcu.BuiltinDecl = switch (stage) {
+            .main => .Type,
+            .panic => .Panic,
+            .va_list => .VaList,
         };
-        if (val != .none) return;
+        if (zcu.builtin_decl_values.get(to_check) != .none) return;
     }
 
     const any_changed: bool, const new_failed: bool = if (pt.analyzeMemoizedState(stage)) |any_changed|
src/Sema.zig
@@ -27612,13 +27612,8 @@ fn explainWhyTypeIsNotPacked(
 fn preparePanicId(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.PanicId) !InternPool.Index {
     const zcu = sema.pt.zcu;
     try sema.ensureMemoizedStateResolved(src, .panic);
-    try zcu.ensureFuncBodyAnalysisQueued(zcu.builtin_decl_values.@"Panic.call");
-    switch (panic_id) {
-        inline else => |ct_panic_id| {
-            const name = "Panic.messages." ++ @tagName(ct_panic_id);
-            return @field(zcu.builtin_decl_values, name);
-        },
-    }
+    try zcu.ensureFuncBodyAnalysisQueued(zcu.builtin_decl_values.get(.@"Panic.call"));
+    return zcu.builtin_decl_values.get(panic_id.toBuiltin());
 }
 
 fn addSafetyCheck(
@@ -27723,9 +27718,9 @@ fn panicWithMsg(sema: *Sema, block: *Block, src: LazySrcLoc, msg_inst: Air.Inst.
     }
 
     try sema.ensureMemoizedStateResolved(src, .panic);
-    try zcu.ensureFuncBodyAnalysisQueued(zcu.builtin_decl_values.@"Panic.call");
+    try zcu.ensureFuncBodyAnalysisQueued(zcu.builtin_decl_values.get(.@"Panic.call"));
 
-    const panic_fn = Air.internedToRef(zcu.builtin_decl_values.@"Panic.call");
+    const panic_fn = Air.internedToRef(zcu.builtin_decl_values.get(.@"Panic.call"));
     const null_stack_trace = Air.internedToRef(zcu.null_stack_trace);
 
     const opt_usize_ty = try pt.optionalType(.usize_type);
@@ -38720,15 +38715,15 @@ const ComptimeLoadResult = @import("Sema/comptime_ptr_access.zig").ComptimeLoadR
 const storeComptimePtr = @import("Sema/comptime_ptr_access.zig").storeComptimePtr;
 const ComptimeStoreResult = @import("Sema/comptime_ptr_access.zig").ComptimeStoreResult;
 
-pub fn getBuiltinType(sema: *Sema, src: LazySrcLoc, comptime decl: Zcu.BuiltinDecl) SemaError!Type {
-    comptime assert(decl.kind() == .type);
+pub fn getBuiltinType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) SemaError!Type {
+    assert(decl.kind() == .type);
     try sema.ensureMemoizedStateResolved(src, decl.stage());
-    return .fromInterned(@field(sema.pt.zcu.builtin_decl_values, @tagName(decl)));
+    return .fromInterned(sema.pt.zcu.builtin_decl_values.get(decl));
 }
-pub fn getBuiltin(sema: *Sema, src: LazySrcLoc, comptime decl: Zcu.BuiltinDecl) SemaError!InternPool.Index {
-    comptime assert(decl.kind() != .type);
+pub fn getBuiltin(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) SemaError!InternPool.Index {
+    assert(decl.kind() != .type);
     try sema.ensureMemoizedStateResolved(src, decl.stage());
-    return @field(sema.pt.zcu.builtin_decl_values, @tagName(decl));
+    return sema.pt.zcu.builtin_decl_values.get(decl);
 }
 
 pub const NavPtrModifiers = struct {
@@ -38810,7 +38805,7 @@ pub fn analyzeMemoizedState(sema: *Sema, block: *Block, src: LazySrcLoc, builtin
             const parent_ns: Zcu.Namespace.Index, const parent_name: []const u8, const name: []const u8 = switch (comptime builtin_decl.access()) {
                 .direct => |name| .{ builtin_namespace, "std.builtin", name },
                 .nested => |nested| access: {
-                    const parent_ty: Type = .fromInterned(@field(zcu.builtin_decl_values, @tagName(nested[0])));
+                    const parent_ty: Type = .fromInterned(zcu.builtin_decl_values.get(nested[0]));
                     const parent_ns = parent_ty.getNamespace(zcu).unwrap() orelse {
                         return sema.fail(block, src, "std.builtin.{s} is not a container type", .{@tagName(nested[0])});
                     };
@@ -38845,9 +38840,9 @@ pub fn analyzeMemoizedState(sema: *Sema, block: *Block, src: LazySrcLoc, builtin
                 },
             }
 
-            const prev = @field(zcu.builtin_decl_values, @tagName(builtin_decl));
+            const prev = zcu.builtin_decl_values.get(builtin_decl);
             if (val.toIntern() != prev) {
-                @field(zcu.builtin_decl_values, @tagName(builtin_decl)) = val.toIntern();
+                zcu.builtin_decl_values.set(builtin_decl, val.toIntern());
                 any_changed = true;
             }
         }
src/Zcu.zig
@@ -217,8 +217,8 @@ all_type_references: std.ArrayListUnmanaged(TypeReference) = .empty,
 /// Freelist of indices in `all_type_references`.
 free_type_references: std.ArrayListUnmanaged(u32) = .empty,
 
-/// Populated by analysis of `AnalUnit.wrap(.{ .memoized_state = s })`, where `s` depends on the field.
-builtin_decl_values: BuiltinDecl.Memoized = .{},
+/// Populated by analysis of `AnalUnit.wrap(.{ .memoized_state = s })`, where `s` depends on the element.
+builtin_decl_values: BuiltinDecl.Memoized = .initFill(.none),
 /// Populated by analysis of `AnalUnit.wrap(.{ .memoized_state = .panic })`.
 null_stack_trace: InternPool.Index = .none,
 
@@ -420,7 +420,7 @@ pub const BuiltinDecl = enum {
         };
     }
 
-    const Memoized = std.enums.EnumFieldStruct(BuiltinDecl, InternPool.Index, .none);
+    const Memoized = std.enums.EnumArray(BuiltinDecl, InternPool.Index);
 };
 
 pub const PanicId = enum {
@@ -444,6 +444,21 @@ pub const PanicId = enum {
     memcpy_len_mismatch,
     memcpy_alias,
     noreturn_returned,
+
+    pub fn toBuiltin(id: PanicId) BuiltinDecl {
+        const first_msg: PanicId = @enumFromInt(0);
+        const first_decl = @field(BuiltinDecl, "Panic.messages." ++ @tagName(first_msg));
+        comptime {
+            // Ensure that the messages are ordered the same in `BuiltinDecl` as they are here.
+            for (@typeInfo(PanicId).@"enum".fields) |panic_field| {
+                const expect_name = "Panic.messages." ++ panic_field.name;
+                const expect_idx = @intFromEnum(first_decl) + panic_field.value;
+                const actual_idx = @intFromEnum(@field(BuiltinDecl, expect_name));
+                assert(expect_idx == actual_idx);
+            }
+        }
+        return @enumFromInt(@intFromEnum(first_decl) + @intFromEnum(id));
+    }
 };
 
 pub const GlobalErrorSet = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void);