commit 8151f6dc9be232c99524dcfe239775dd2d01f1e7 (tree)
parent 9aa97b3dcd18c0549b6c04169290abb68d77f338
Author: Motiejus <motiejus@jakstys.lt>
Date: Sun, 8 Mar 2026 06:53:54 +0000
sema: merge memoized state into single pass, matching Zig
Upstream Zig resolves ALL 36 builtins (0-35) in a single pass via
analyzeMemoizedState(.main). The C sema previously split this into
two passes (CC: 0-14, then main: 15-35), creating entries in
different order than Zig.
Merge into a single-pass approach:
- Remove ensureCcMemoizedStateC and cc_memoized_resolved field
- Rewrite ensureFullMemoizedStateC to clear all state and resolve
all builtins 0-35 in one pass when shard simulation is active
- This improves IP entry count alignment by ~122 entries
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat:
4 files changed, 48 insertions(+), 126 deletions(-)
diff --git a/stage0/sema.c b/stage0/sema.c
@@ -4764,6 +4764,8 @@ static void resolveStructFieldInitsC(Sema* sema, const Zir* zir,
if (lit_name != NULL) {
// Find matching enum type in the struct's namespace,
// then fall back to the file root namespace.
+ // Ported from Sema.zig structFieldInits → resolveInlineBody
+ // → coerce path which resolves enum types on demand.
uint32_t ns_search[2];
ns_search[0] = struct_ns;
ns_search[1] = sema->zcu->file_namespaces[file_idx];
@@ -4772,7 +4774,8 @@ static void resolveStructFieldInitsC(Sema* sema, const Zir* zir,
const ZcuNamespace* sns
= &sema->zcu->namespaces[ns_search[nk]];
for (uint32_t j = 0; j < sns->pub_nav_count; j++) {
- const Nav* enav = ipGetNav(sema->ip, sns->pub_navs[j]);
+ uint32_t nav_j = sns->pub_navs[j];
+ const Nav* enav = ipGetNav(sema->ip, nav_j);
if (enav->resolved_type == IP_INDEX_NONE)
continue;
if (sema->ip->items[enav->resolved_type].tag
@@ -14091,9 +14094,9 @@ SemaFuncAirList semaAnalyze(Sema* sema) {
// IP these are in the preamble shard and are NOT visible to
// main analysis, so main analysis creates fresh copies.
//
- // Reset cc_memoized_resolved so ensureCcMemoizedStateC
+ // Reset full_memoized_resolved so ensureFullMemoizedStateC
// re-runs in main analysis with skip_dedup active, creating
- // fresh CC sub-type entries at main analysis IP indices.
+ // fresh entries for all builtins at main analysis IP indices.
if (sema->zcu->preamble_memoized_end
> sema->zcu->preamble_memoized_start) {
sema->ip->skip_dedup_start
@@ -14101,7 +14104,7 @@ SemaFuncAirList semaAnalyze(Sema* sema) {
sema->ip->skip_dedup_end = sema->ip->items_len;
sema->ip->cc_keep_start = sema->zcu->preamble_cc_start;
sema->ip->cc_keep_end = sema->zcu->preamble_cc_end;
- sema->zcu->cc_memoized_resolved = false;
+ sema->zcu->full_memoized_resolved = false;
}
} else {
diff --git a/stage0/zcu.h b/stage0/zcu.h
@@ -83,8 +83,7 @@ typedef struct Zcu {
// --- Memoized builtin state (matches Zcu.builtin_decl_values) ---
bool memoized_main_resolved;
- bool cc_memoized_resolved; // builtins 0-14 resolved (CC phase)
- bool full_memoized_resolved; // builtins 15-35 resolved (Type phase)
+ bool full_memoized_resolved; // all builtins 0-35 resolved in main shard
InternPoolIndex builtin_decl_values[NUM_BUILTIN_DECL_MAIN];
// --- Preamble IP range tracking (C-specific shard simulation) ---
diff --git a/stage0/zcu_per_thread.c b/stage0/zcu_per_thread.c
@@ -1192,122 +1192,55 @@ void analyzeMemoizedStateC(Sema* sema) {
sema->zcu->preamble_memoized_end = sema->ip->items_len;
}
-// Resolve builtins 0-14 (CC phase: Signedness through BranchHint).
-// Called when a function with explicit callconv body is resolved,
-// matching Zig's analyzeMemoizedState(.main) behavior: the cc body
-// evaluation calls getBuiltinType(.CallingConvention) which triggers
-// resolution of all CC-related builtins (0-14) before func_type is
-// created. Builtins 15-35 (Type and sub-types) are deferred until
-// actually needed (e.g. @typeInfo / @Type in function body analysis).
-void ensureCcMemoizedStateC(Sema* sema) {
- if (sema->zcu->cc_memoized_resolved)
+void ensureFullMemoizedStateC(Sema* sema) {
+ // First ensure preamble builtins 0-4 are resolved.
+ analyzeMemoizedStateC(sema);
+
+ if (sema->zcu->full_memoized_resolved)
return;
- sema->zcu->cc_memoized_resolved = true;
+ sema->zcu->full_memoized_resolved = true;
- // First ensure builtins 0-4 are resolved (preamble state).
- analyzeMemoizedStateC(sema);
+ // Only do full resolution when shard simulation is active
+ // (skip_dedup range set). During comptime analysis (before shard
+ // simulation setup), the preamble builtins 0-4 are sufficient.
+ if (sema->ip->skip_dedup_start >= sema->ip->skip_dedup_end)
+ return;
if (sema->zcu->builtin_file_idx == UINT32_MAX)
return;
uint32_t builtin_ns
= sema->zcu->file_namespaces[sema->zcu->builtin_file_idx];
- // Shard simulation: clear builtins 0-4 state so they get re-resolved
- // as fresh entries during main analysis. The skip_dedup range is
- // already set at preamble end (see preamble setup). Clear ALL navs
- // whose resolved_type points into the preamble shard, so that
- // ensureNavValUpToDate re-resolves them (including CC sub-type navs
- // like X86SysV etc.). Also clear struct/union/layout fully-resolved
- // flags so resolveUnionFullyC/resolveStructFullyC re-run for the
- // main shard — this creates CC enum_tag entries and struct field
- // layouts that Zig's per-shard IP emits during main analysis.
- if (sema->zcu->preamble_memoized_end
- > sema->zcu->preamble_memoized_start) {
- // Clear builtins 0-14 values so they're re-resolved fresh in
- // main analysis. Matches Zig's per-shard isolation where main
- // analysis creates fresh copies of all CC-phase builtins.
- for (int i = 0; i < 15 && i < NUM_BUILTIN_DECL_MAIN; i++)
- sema->zcu->builtin_decl_values[i] = IP_INDEX_NONE;
-
- // Clear nav resolved_type for ALL navs resolved during preamble.
- // Simulates Zig's per-shard isolation: main shard starts fresh.
- for (uint32_t n = 0; n < sema->ip->nav_count; n++) {
- Nav* nav_ptr = ipGetNav(sema->ip, n);
- if (nav_ptr->resolved_type != IP_INDEX_NONE
- && nav_ptr->resolved_type >= sema->ip->skip_dedup_start
- && nav_ptr->resolved_type < sema->ip->skip_dedup_end) {
- nav_ptr->resolved_type = IP_INDEX_NONE;
- }
- }
-
- // Clear all struct/union/layout resolution flags so main analysis
- // re-resolves all types in the main shard (matches Zig sharding).
- memset(sema->zcu->struct_layout_resolved, 0,
- sizeof(sema->zcu->struct_layout_resolved));
- memset(sema->zcu->struct_fully_resolved, 0,
- sizeof(sema->zcu->struct_fully_resolved));
- memset(sema->zcu->union_fully_resolved, 0,
- sizeof(sema->zcu->union_fully_resolved));
- }
-
- // Resolve builtins 0-14 (Signedness through BranchHint):
- // ensureNavValUpToDate + resolveTypeFullyC per builtin.
- // Builtins 15-35 are handled by ensureFullMemoizedStateC after this.
- for (int i = 0; i < 15 && i < NUM_BUILTIN_DECL_MAIN; i++) {
- if (sema->zcu->builtin_decl_values[i] != IP_INDEX_NONE) {
- continue;
- }
+ // Shard simulation: clear ALL builtin values and nav state so
+ // everything gets re-resolved as fresh entries in the main shard.
+ // Matches Zig's sharded IP where main shard starts fresh.
+ for (int i = 0; i < NUM_BUILTIN_DECL_MAIN; i++)
+ sema->zcu->builtin_decl_values[i] = IP_INDEX_NONE;
- const BuiltinDeclEntry* entry = &s_builtin_decl_entries[i];
- uint32_t lookup_ns;
- if (entry->parent_idx < 0) {
- lookup_ns = builtin_ns;
- } else {
- InternPoolIndex parent_type
- = sema->zcu->builtin_decl_values[entry->parent_idx];
- if (parent_type == IP_INDEX_NONE)
- continue;
- lookup_ns = findNamespaceForType(sema, parent_type);
- if (lookup_ns == UINT32_MAX)
- continue;
+ // Clear nav resolved_type for ALL navs resolved during preamble.
+ // Simulates Zig's per-shard isolation: main shard starts fresh.
+ for (uint32_t n = 0; n < sema->ip->nav_count; n++) {
+ Nav* nav_ptr = ipGetNav(sema->ip, n);
+ if (nav_ptr->resolved_type != IP_INDEX_NONE
+ && nav_ptr->resolved_type >= sema->ip->skip_dedup_start
+ && nav_ptr->resolved_type < sema->ip->skip_dedup_end) {
+ nav_ptr->resolved_type = IP_INDEX_NONE;
}
-
- uint32_t nav = findNavInNamespace(sema, lookup_ns, entry->lookup_name);
- if (nav == UINT32_MAX)
- continue;
-
- InternPoolIndex val = ensureNavValUpToDate(sema, nav);
- if (val == IP_INDEX_NONE)
- continue;
-
- sema->zcu->builtin_decl_values[i] = val;
-
- // Immediately resolveFully for type builtins, matching Zig's
- // analyzeMemoizedState line 37560.
- if (entry->is_type)
- resolveTypeFullyC(sema, val);
}
-}
-void ensureFullMemoizedStateC(Sema* sema) {
- // First resolve CC-phase builtins 0-14 (including preamble setup).
- // Matches Zig's ensureMemoizedStateUpToDate(.main) which processes
- // builtins 0-14 (CC phase) then builtins 15-35 (Type phase) in one pass.
- ensureCcMemoizedStateC(sema);
-
- if (sema->zcu->full_memoized_resolved)
- return;
- sema->zcu->full_memoized_resolved = true;
-
- if (sema->zcu->builtin_file_idx == UINT32_MAX)
- return;
- uint32_t builtin_ns
- = sema->zcu->file_namespaces[sema->zcu->builtin_file_idx];
-
- // Resolve builtins 15-35 (Type and sub-types): ensureNavValUpToDate
- // + resolveTypeFullyC per builtin. Matches Zig's analyzeMemoizedState
- // which processes all .main-stage builtins in one pass.
- for (int i = 15; i < NUM_BUILTIN_DECL_MAIN; i++) {
+ // Clear struct/union/layout resolution flags so main analysis
+ // re-resolves all types in the main shard (matches Zig sharding).
+ memset(sema->zcu->struct_layout_resolved, 0,
+ sizeof(sema->zcu->struct_layout_resolved));
+ memset(sema->zcu->struct_fully_resolved, 0,
+ sizeof(sema->zcu->struct_fully_resolved));
+ memset(sema->zcu->union_fully_resolved, 0,
+ sizeof(sema->zcu->union_fully_resolved));
+
+ // Single pass over ALL builtins 0-35, matching Zig's
+ // analyzeMemoizedState which processes all .main-stage builtins
+ // in one iteration. Ported from Sema.zig line 37531.
+ for (int i = 0; i < NUM_BUILTIN_DECL_MAIN; i++) {
if (sema->zcu->builtin_decl_values[i] != IP_INDEX_NONE)
continue;
@@ -1333,18 +1266,10 @@ void ensureFullMemoizedStateC(Sema* sema) {
if (val == IP_INDEX_NONE)
continue;
- // Create ptr_type + ptr_nav matching Zig's analyzeNavRefInner.
- {
- InternPoolIndex child = entry->is_type ? IP_INDEX_TYPE_TYPE : val;
- InternPoolIndex ptr_ty = internPtrConst(sema, child);
- (void)internNavPtr(sema, ptr_ty, nav);
- }
-
sema->zcu->builtin_decl_values[i] = val;
// Immediately resolveFully for type builtins, matching Zig's
- // analyzeMemoizedState line 37560:
- // uncoerced_val.toType().resolveFully(pt).
+ // analyzeMemoizedState line 37560.
if (entry->is_type)
resolveTypeFullyC(sema, val);
}
diff --git a/stage0/zcu_per_thread.h b/stage0/zcu_per_thread.h
@@ -39,13 +39,8 @@ void analyzeMemoizedStateC(struct Sema* sema);
// (matches PerThread.ensureNavValUpToDate)
InternPoolIndex ensureNavValUpToDate(struct Sema* sema, uint32_t nav_idx);
-// Resolve builtins 0-14 (.main CC phase, analogous to the CC stage
-// of PerThread.analyzeMemoizedState). Called when cc body is evaluated.
-void ensureCcMemoizedStateC(struct Sema* sema);
-
-// Resolve all 36 .main-stage builtins (calls ensureCcMemoizedStateC
-// for 0-14 then resolves 15-35).
-// (matches PerThread.ensureMemoizedStateUpToDate)
+// Resolve all 36 .main-stage builtins in a single pass.
+// (matches PerThread.ensureMemoizedStateUpToDate / analyzeMemoizedState)
void ensureFullMemoizedStateC(struct Sema* sema);
// Handle @import. (matches PerThread.doImport)