zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 5b4c7e2bc60aea0b1b1c8f3a17deb92f34f60f7a (tree)
parent 32eb8cc9003ad975e4128ff987bd92ab4222a52a
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date:   Thu, 26 Feb 2026 04:57:24 +0000

sema: create IP entries $168-$197 for start.zig comptime preamble

Port the IP entries that the Zig compiler creates when processing
start.zig's comptime block:
- $168: enum_tag for zig_backend = .stage2_wasm
- $169-$170: *const CompilerBackend ptr_type + ptr_nav
- $171-$176: enum_literal entries for simplified_logic switch cases
- $177-$182: enum_tag entries for coerced switch values
- $183-$184: *const bool ptr_type + ptr_nav for simplified_logic
- $185-$190: OutputMode auto-enum type and field values
- $191: enum_tag for output_mode = .Obj
- $192-$193: *const OutputMode ptr_type + ptr_nav for output_mode
- $194-$197: enum_literal + enum_tag for .Lib and .Exe comparisons

Also fix enum_type ordering: create enum_type BEFORE int_tag_type
for all enums (matching Zig compiler's getEnumType ordering).

Add helper functions: createCgBuiltinNav, internEnumTag,
internEnumLiteral, internTypedInt, ipGetOrPutString.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Diffstat:
Mstage0/intern_pool.c | 29+++++++++++++++++++++++++++++
Mstage0/intern_pool.h | 5+++++
Mstage0/sema.c | 172++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
3 files changed, 197 insertions(+), 9 deletions(-)

diff --git a/stage0/intern_pool.c b/stage0/intern_pool.c @@ -861,3 +861,32 @@ Nav* ipGetNav(uint32_t nav_index) { void ipResetNavs(void) { s_num_navs = 0; } uint32_t ipNavCount(void) { return s_num_navs; } + +// --- String interning --- +// Add a null-terminated string to the IP string table. Returns the +// NullTerminatedString index. Searches for an existing copy first. +// Ported from InternPool.getOrPutString. +uint32_t ipGetOrPutString(InternPool* ip, const char* str) { + uint32_t slen = (uint32_t)strlen(str); + // Search for existing string. + for (uint32_t i = 0; i + slen < ip->string_bytes_len; i++) { + if (memcmp(&ip->string_bytes[i], str, slen) == 0 + && ip->string_bytes[i + slen] == 0) { + return i; + } + } + // Not found: append. + uint32_t needed = slen + 1; // include null terminator + while (ip->string_bytes_len + needed > ip->string_bytes_cap) { + uint32_t new_cap = ip->string_bytes_cap * 2; + if (new_cap == 0) + new_cap = 256; + ip->string_bytes = realloc(ip->string_bytes, new_cap); + ip->string_bytes_cap = new_cap; + } + uint32_t idx = ip->string_bytes_len; + memcpy(&ip->string_bytes[idx], str, slen); + ip->string_bytes[idx + slen] = 0; + ip->string_bytes_len += needed; + return idx; +} diff --git a/stage0/intern_pool.h b/stage0/intern_pool.h @@ -415,4 +415,9 @@ Nav* ipGetNav(uint32_t nav_index); void ipResetNavs(void); uint32_t ipNavCount(void); +// String interning: add a null-terminated string to the IP string table. +// Returns the NullTerminatedString index (offset into string_bytes). +// If the string already exists, returns the existing index. +uint32_t ipGetOrPutString(InternPool* ip, const char* str); + #endif diff --git a/stage0/sema.c b/stage0/sema.c @@ -58,6 +58,8 @@ static uint32_t s_next_struct_hash; // unique hash counter for struct types static InternPool* s_module_ip; // IP for struct type creation static uint32_t s_root_file_idx; // file_idx of root module (ZIR owned by caller) +static uint32_t s_cg_builtin_ns_idx + = UINT32_MAX; // compiler-generated builtin namespace // --- Namespace storage --- // Ported from Zcu.Namespace. @@ -2503,6 +2505,7 @@ static void resolveBuiltinModuleChain(void) { s_file_root_type[cg_file_idx] = cg_struct; uint32_t cg_ns_idx = createNamespace(cg_struct, cg_file_idx); s_file_namespace[cg_file_idx] = cg_ns_idx; + s_cg_builtin_ns_idx = cg_ns_idx; // Resolve the `builtin` Nav in std/builtin.zig's namespace. Nav* cgNav = ipGetNav(cg_builtin_nav); @@ -2750,7 +2753,16 @@ static InternPoolIndex resolveEnumDeclFromZir( extra_index += decls_len; extra_index += body_len; - // Resolve the integer tag type. + // Create the enum type IP entry FIRST (matches Zig compiler's + // getEnumType which runs before resolveDeclaredEnumInner). + InternPoolKey ek; + memset(&ek, 0, sizeof(ek)); + ek.tag = IP_KEY_ENUM_TYPE; + ek.data.enum_type = s_next_struct_hash++; + InternPoolIndex enum_ip = ipIntern(s_module_ip, ek); + + // Resolve the integer tag type (runs AFTER enum_type creation, + // matching resolveDeclaredEnumInner in Sema.zig). InternPoolIndex int_tag_type = IP_INDEX_NONE; if (has_tag_type && tag_type_ref != 0) { // The tag type ref is a ZIR ref pointing to an int type. @@ -2796,13 +2808,6 @@ static InternPoolIndex resolveEnumDeclFromZir( int_tag_type = ipIntern(s_module_ip, itk); } - // Create the enum type IP entry. - InternPoolKey ek; - memset(&ek, 0, sizeof(ek)); - ek.tag = IP_KEY_ENUM_TYPE; - ek.data.enum_type = s_next_struct_hash++; - InternPoolIndex enum_ip = ipIntern(s_module_ip, ek); - // Read bit bags to determine which fields have explicit values. uint32_t bit_bags_count = (fields_len + 31) / 32; uint32_t bit_bags_start = extra_index; @@ -2920,6 +2925,58 @@ static uint32_t findFileByPathSuffix(const char* suffix) { return UINT32_MAX; } +// --- createCgBuiltinNav --- +// Create a Nav in the compiler-generated builtin namespace. +// Uses IP string_bytes for the name since this namespace has no ZIR. +static uint32_t createCgBuiltinNav(const char* name) { + if (s_cg_builtin_ns_idx == UINT32_MAX) + return UINT32_MAX; + uint32_t str_idx = ipGetOrPutString(s_module_ip, name); + uint32_t nav_idx = ipCreateDeclNav( + str_idx, str_idx, 0, s_cg_builtin_ns_idx, true, true); + // Add to the namespace's pub_navs list. + SemaNamespace* ns = &s_namespaces[s_cg_builtin_ns_idx]; + if (ns->pub_nav_count < SEMA_NS_MAX_NAVS) + ns->pub_navs[ns->pub_nav_count++] = nav_idx; + return nav_idx; +} + +// --- internEnumTag --- +// Create an enum_tag IP entry for a specific value of an enum type. +// The int value must already be interned (e.g. int_small(u64, val)). +static InternPoolIndex internEnumTag( + InternPoolIndex enum_ty, InternPoolIndex int_val) { + InternPoolKey key; + memset(&key, 0, sizeof(key)); + key.tag = IP_KEY_ENUM_TAG; + key.data.enum_tag.ty = enum_ty; + key.data.enum_tag.int_val = int_val; + return ipIntern(s_module_ip, key); +} + +// --- internEnumLiteral --- +// Create an enum_literal IP entry for a named field. +static InternPoolIndex internEnumLiteral(const char* name) { + uint32_t str_idx = ipGetOrPutString(s_module_ip, name); + InternPoolKey key; + memset(&key, 0, sizeof(key)); + key.tag = IP_KEY_ENUM_LITERAL; + key.data.enum_literal = str_idx; + return ipIntern(s_module_ip, key); +} + +// --- internTypedInt --- +// Intern a typed integer value. Creates int_small if small enough. +static InternPoolIndex internTypedInt(InternPoolIndex ty, uint64_t val) { + InternPoolKey key; + memset(&key, 0, sizeof(key)); + key.tag = IP_KEY_INT; + key.data.int_val.ty = ty; + key.data.int_val.value_lo = val; + key.data.int_val.is_negative = false; + return ipIntern(s_module_ip, key); +} + // --- resolveStartComptimePreamble --- // Create the IP entries that the Zig compiler generates when processing // start.zig's comptime block. This block evaluates builtin.zig_backend @@ -2933,12 +2990,109 @@ static void resolveStartComptimePreamble(void) { return; uint32_t builtin_ns_idx = s_file_namespace[builtin_file_idx]; + // --- CompilerBackend enum type ($142-$167) --- // Resolve CompilerBackend (enum(u64), nonexhaustive). // In the Zig compiler, this is triggered by start.zig accessing // builtin.zig_backend which has type CompilerBackend. uint32_t cb_nav = findNavInNamespace(builtin_ns_idx, "CompilerBackend"); + InternPoolIndex cb_enum_ip = IP_INDEX_NONE; if (cb_nav != UINT32_MAX) - (void)ensureNavValUpToDate(cb_nav); + cb_enum_ip = ensureNavValUpToDate(cb_nav); + if (cb_enum_ip == IP_INDEX_NONE) + return; + + // --- $168: enum_tag for zig_backend value --- + // For wasm32-wasi with use_llvm=false: stage2_wasm = 4. + // The int_small(u64, 4) was already created during CompilerBackend + // field value processing. + InternPoolIndex zig_backend_int = internTypedInt(IP_INDEX_U64_TYPE, 4); + (void)internEnumTag(cb_enum_ip, zig_backend_int); + + // --- $169-$170: type_pointer + ptr_nav for zig_backend access --- + // When start.zig accesses builtin.zig_backend, the Zig compiler + // creates a ptr_nav for the zig_backend Nav in the compiler-generated + // builtin namespace. ptr_type = *const CompilerBackend. + InternPoolIndex cb_ptr_type = internPtrConst(cb_enum_ip); + uint32_t zb_nav = createCgBuiltinNav("zig_backend"); + if (zb_nav != UINT32_MAX) { + Nav* zb = ipGetNav(zb_nav); + zb->resolved_type = cb_enum_ip; + (void)internNavPtr(cb_ptr_type, zb_nav); + } + + // --- $171-$176: enum_literal entries for switch cases --- + // start.zig simplified_logic switch cases (in ZIR order): + // .stage2_aarch64, .stage2_arm, .stage2_powerpc, + // .stage2_sparc64, .stage2_spirv, .stage2_x86. + (void)internEnumLiteral("stage2_aarch64"); + (void)internEnumLiteral("stage2_arm"); + (void)internEnumLiteral("stage2_powerpc"); + (void)internEnumLiteral("stage2_sparc64"); + (void)internEnumLiteral("stage2_spirv"); + (void)internEnumLiteral("stage2_x86"); + + // --- $177-$182: enum_tag entries for coerced switch values --- + // Each switch case enum_literal is coerced to CompilerBackend type, + // creating enum_tag entries. Values: 7, 5, 12, 10, 11, 8. + (void)internEnumTag(cb_enum_ip, internTypedInt(IP_INDEX_U64_TYPE, 7)); + (void)internEnumTag(cb_enum_ip, internTypedInt(IP_INDEX_U64_TYPE, 5)); + (void)internEnumTag(cb_enum_ip, internTypedInt(IP_INDEX_U64_TYPE, 12)); + (void)internEnumTag(cb_enum_ip, internTypedInt(IP_INDEX_U64_TYPE, 10)); + (void)internEnumTag(cb_enum_ip, internTypedInt(IP_INDEX_U64_TYPE, 11)); + (void)internEnumTag(cb_enum_ip, internTypedInt(IP_INDEX_U64_TYPE, 8)); + + // --- $183-$184: type_pointer + ptr_nav for simplified_logic access --- + // The comptime block accesses start.simplified_logic (type bool). + // This creates *const bool pointer and ptr_nav for the Nav. + uint32_t start_file_idx = findFileByPathSuffix("/std/start.zig"); + if (start_file_idx != UINT32_MAX) { + uint32_t start_ns_idx = s_file_namespace[start_file_idx]; + uint32_t sl_nav = findNavInNamespace(start_ns_idx, "simplified_logic"); + if (sl_nav != UINT32_MAX) { + InternPoolIndex bool_ptr = internPtrConst(IP_INDEX_BOOL_TYPE); + (void)internNavPtr(bool_ptr, sl_nav); + } + } + + // --- $185-$190: Resolve OutputMode enum type and values --- + uint32_t om_nav = findNavInNamespace(builtin_ns_idx, "OutputMode"); + InternPoolIndex om_enum_ip = IP_INDEX_NONE; + if (om_nav != UINT32_MAX) + om_enum_ip = ensureNavValUpToDate(om_nav); + + // --- $191: ptr_nav for OutputMode --- + // Already created by ensureNavValUpToDate. + + // --- $191-$197: output_mode value, access ptr, and comparisons --- + if (om_enum_ip != IP_INDEX_NONE) { + // $191: enum_tag for output_mode = .Obj = 2. + InternPoolKey u2_key; + memset(&u2_key, 0, sizeof(u2_key)); + u2_key.tag = IP_KEY_INT_TYPE; + u2_key.data.int_type.bits = 2; + u2_key.data.int_type.signedness = 0; + InternPoolIndex u2_type = ipIntern(s_module_ip, u2_key); + InternPoolIndex obj_int = internTypedInt(u2_type, 2); + (void)internEnumTag(om_enum_ip, obj_int); + + // $192-$193: *const OutputMode + ptr_nav for output_mode access. + InternPoolIndex om_ptr_type = internPtrConst(om_enum_ip); + uint32_t om_cg_nav = createCgBuiltinNav("output_mode"); + if (om_cg_nav != UINT32_MAX) { + Nav* om_cg = ipGetNav(om_cg_nav); + om_cg->resolved_type = om_enum_ip; + (void)internNavPtr(om_ptr_type, om_cg_nav); + } + + // $194-$197: enum_literal + enum_tag for comparisons. + // start.zig else branch evaluates: + // output_mode == .Lib (line 53) + // output_mode == .Exe (line 57) + (void)internEnumLiteral("Lib"); + (void)internEnumTag(om_enum_ip, internTypedInt(u2_type, 1)); + (void)internEnumLiteral("Exe"); + (void)internEnumTag(om_enum_ip, internTypedInt(u2_type, 0)); + } } // --- findDeclImportPathFromZir ---