sema: support non-inline callee body analysis (tests 78-81)

Add analyzeFuncBodyAndRecord helper to analyze non-inline function
callees in a fresh AIR context and record them to func_air_list.
Simplify zirFunc to use parseFuncZir + analyzeFuncBodyAndRecord.

In zirCall, generic functions are correctly treated as runtime calls
(not auto-inlined), matching upstream Sema.zig:7482 behavior where
is_inline_call = block.isComptime() or inline_requested.

Also includes pre-existing uncommitted changes:
- SemaBlock inline instructions array (avoid heap for small blocks)
- StructFieldInfo.fields[].name as fixed-size char[64]

num_sema_passing: 78 -> 82

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-23 23:36:16 +00:00
parent 2327ebbf15
commit 0752084621
3 changed files with 137 additions and 254 deletions

View File

@@ -203,7 +203,7 @@ pub const files = [_][]const u8{
"lib/std/math/expo2.zig", // 995
};
pub const num_sema_passing: usize = 78;
pub const num_sema_passing: usize = 82;
pub const sema_unit_tests = [_][]const u8{
"stage0/sema_tests/empty.zig",

View File

@@ -15,15 +15,6 @@
} \
} while (0)
// Duplicate a string using malloc (strdup is not available in C11).
static char* dupString(const char* s) {
size_t len = strlen(s) + 1;
char* copy = malloc(len);
if (copy)
memcpy(copy, s, len);
return copy;
}
// Simple djb2 hash for enum literal names.
static uint32_t simpleStringHash(const char* s) {
uint32_t h = 5381;
@@ -36,7 +27,6 @@ static uint32_t simpleStringHash(const char* s) {
#define SEMA_AIR_INITIAL_CAP 256
#define SEMA_AIR_EXTRA_INITIAL_CAP 256
#define SEMA_BLOCK_INITIAL_CAP 64
#define INST_MAP_INITIAL_CAP 32
// Exported declaration names collected by ZIR_INST_EXPORT handler.
@@ -62,10 +52,6 @@ void semaInit(Sema* sema, InternPool* ip, Zir code) {
}
void semaDeinit(Sema* sema) {
for (uint32_t i = 0; i < sema->num_struct_info; i++) {
for (uint32_t f = 0; f < sema->struct_info[i].num_fields; f++)
free((char*)sema->struct_info[i].fields[f].name);
}
free(sema->air_inst_tags);
free(sema->air_inst_datas);
free(sema->air_extra);
@@ -250,8 +236,9 @@ static void semaBlockInit(SemaBlock* block, Sema* sema, SemaBlock* parent) {
memset(block, 0, sizeof(*block));
block->sema = sema;
block->parent = parent;
block->instructions = ARR_INIT(uint32_t, SEMA_BLOCK_INITIAL_CAP);
block->instructions = block->inline_instructions;
block->instructions_cap = SEMA_BLOCK_INITIAL_CAP;
block->instructions_on_heap = false;
block->is_comptime = true; // Module-level analysis is comptime.
block->error_return_trace_index = AIR_REF_NONE;
// Ported from Sema.zig makeSubBlock: inherit need_debug_scope from parent.
@@ -260,12 +247,30 @@ static void semaBlockInit(SemaBlock* block, Sema* sema, SemaBlock* parent) {
}
static void semaBlockDeinit(SemaBlock* block) {
free(block->instructions);
if (block->instructions_on_heap)
free(block->instructions);
block->instructions = NULL;
block->instructions_len = 0;
block->instructions_cap = 0;
}
// Grow a block's instruction buffer, handling the inline→heap transition.
static void semaBlockGrowInstructions(SemaBlock* block, uint32_t new_cap) {
if (block->instructions_on_heap) {
block->instructions
= realloc(block->instructions, new_cap * sizeof(uint32_t));
} else {
uint32_t* heap = malloc(new_cap * sizeof(uint32_t));
memcpy(heap, block->inline_instructions,
block->instructions_len * sizeof(uint32_t));
block->instructions = heap;
block->instructions_on_heap = true;
}
if (!block->instructions)
exit(1);
block->instructions_cap = new_cap;
}
// Add an AIR instruction to the block's instruction list.
static AirInstRef semaAddInst(
SemaBlock* block, AirInstTag inst_tag, AirInstData data) {
@@ -275,12 +280,7 @@ static AirInstRef semaAddInst(
// Append to block's instruction list.
if (block->instructions_len >= block->instructions_cap) {
uint32_t new_cap = block->instructions_cap * 2;
uint32_t* new_insts
= realloc(block->instructions, new_cap * sizeof(uint32_t));
if (!new_insts)
exit(1);
block->instructions = new_insts;
block->instructions_cap = new_cap;
semaBlockGrowInstructions(block, new_cap);
}
block->instructions[block->instructions_len++] = idx;
@@ -469,6 +469,8 @@ static bool analyzeBodyInner(
static uint8_t analyzeBodyRuntimeBreak(
Sema* sema, SemaBlock* block, const uint32_t* body, uint32_t body_len);
static uint16_t floatBits(TypeIndex ty);
static void analyzeFuncBodyAndRecord(
Sema* sema, SemaBlock* block, uint32_t func_inst, uint32_t name_idx);
// getParamBody: extract param body from a param_block ZIR instruction.
// Ported from lib/std/zig/Zir.zig getParamBody.
@@ -2743,8 +2745,7 @@ static InternPoolIndex registerStructTypeFromZir(
// Read field_name.
uint32_t fn_idx = zir->extra[ni];
ni++;
info->fields[f].name
= dupString((const char*)&zir->string_bytes[fn_idx]);
info->fields[f].name = (const char*)&zir->string_bytes[fn_idx];
if (!has_type_body) {
// Simple type ref.
uint32_t type_ref = zir->extra[ni];
@@ -4211,9 +4212,9 @@ static AirInstRef zirCall(
info->struct_type = struct_ip;
info->ptr_type = ptr_ip;
info->num_fields = 2;
info->fields[0].name = dupString("real");
info->fields[0].name = "real";
info->fields[0].type = elem_ty;
info->fields[1].name = dupString("imag");
info->fields[1].name = "imag";
info->fields[1].type = elem_ty;
}
result_type = struct_ip;
@@ -4353,6 +4354,10 @@ static AirInstRef zirCall(
= (ret_ty == IP_INDEX_TYPE_TYPE || ret_ty == IP_INDEX_COMPTIME_INT_TYPE
|| ret_ty == IP_INDEX_COMPTIME_FLOAT_TYPE
|| ret_ty == IP_INDEX_ENUM_LITERAL_TYPE);
// Upstream (Sema.zig:7482):
// is_inline_call = block.isComptime() or inline_requested;
// Generic functions are NOT auto-inlined — they get monomorphized
// and called at runtime (like regular functions minus comptime params).
bool is_inline_call
= func_info.is_inline || block->is_comptime || is_comptime_only_ret;
if (!is_inline_call) {
@@ -4459,6 +4464,13 @@ static AirInstRef zirCall(
sema->num_calls++;
}
// Trigger separate body analysis of the callee function.
// Ported from Sema.zig analyzeCall: ensureFuncBodyAnalysisQueued.
// Skip for generic functions — they get monomorphized by the full
// compiler but are not separate function entries in the AIR output.
if (!is_generic)
analyzeFuncBodyAndRecord(sema, block, func_inst, callee_name_idx);
// Clean up cross-module state.
if (is_cross_module) {
sema->code = saved_code;
@@ -4729,9 +4741,7 @@ static AirInstRef zirCall(
for (uint32_t i = 0; i < child_block.instructions_len; i++) {
if (block->instructions_len >= block->instructions_cap) {
uint32_t nc = block->instructions_cap * 2;
block->instructions
= realloc(block->instructions, nc * sizeof(uint32_t));
block->instructions_cap = nc;
semaBlockGrowInstructions(block, nc);
}
block->instructions[block->instructions_len++]
= child_block.instructions[i];
@@ -4749,9 +4759,7 @@ static AirInstRef zirCall(
sema->air_inst_datas[block_inst_idx].ty_pl.payload = es;
if (block->instructions_len >= block->instructions_cap) {
uint32_t nc = block->instructions_cap * 2;
block->instructions
= realloc(block->instructions, nc * sizeof(uint32_t));
block->instructions_cap = nc;
semaBlockGrowInstructions(block, nc);
}
block->instructions[block->instructions_len++] = block_inst_idx;
call_result = AIR_REF_FROM_INST(block_inst_idx);
@@ -4770,9 +4778,7 @@ static AirInstRef zirCall(
i++) {
if (block->instructions_len >= block->instructions_cap) {
uint32_t nc = block->instructions_cap * 2;
block->instructions = realloc(
block->instructions, nc * sizeof(uint32_t));
block->instructions_cap = nc;
semaBlockGrowInstructions(block, nc);
}
block->instructions[block->instructions_len++]
= child_block.instructions[i];
@@ -4804,9 +4810,7 @@ static AirInstRef zirCall(
}
if (block->instructions_len >= block->instructions_cap) {
uint32_t nc = block->instructions_cap * 2;
block->instructions
= realloc(block->instructions, nc * sizeof(uint32_t));
block->instructions_cap = nc;
semaBlockGrowInstructions(block, nc);
}
block->instructions[block->instructions_len++] = block_inst_idx;
call_result = result_ref;
@@ -4827,9 +4831,7 @@ static AirInstRef zirCall(
sema->air_inst_datas[block_inst_idx].ty_pl.payload = es;
if (block->instructions_len >= block->instructions_cap) {
uint32_t nc = block->instructions_cap * 2;
block->instructions
= realloc(block->instructions, nc * sizeof(uint32_t));
block->instructions_cap = nc;
semaBlockGrowInstructions(block, nc);
}
block->instructions[block->instructions_len++] = block_inst_idx;
call_result = AIR_REF_FROM_INST(block_inst_idx);
@@ -4853,9 +4855,7 @@ static AirInstRef zirCall(
sema->air_inst_datas[block_inst_idx].ty_pl.payload = es;
if (block->instructions_len >= block->instructions_cap) {
uint32_t nc = block->instructions_cap * 2;
block->instructions
= realloc(block->instructions, nc * sizeof(uint32_t));
block->instructions_cap = nc;
semaBlockGrowInstructions(block, nc);
}
block->instructions[block->instructions_len++] = block_inst_idx;
call_result = AIR_REF_FROM_INST(block_inst_idx);
@@ -4879,100 +4879,37 @@ static AirInstRef zirCall(
return call_result;
}
// zirFunc: analyze a function declaration.
// Ported from src/Sema.zig zirFunc / zirFuncFancy / analyzeFnBodyInner.
// Handles ZIR_INST_FUNC, ZIR_INST_FUNC_INFERRED, and ZIR_INST_FUNC_FANCY.
// For the bootstrap, we only fully analyze exported functions with bodies.
// The function body is analyzed in a fresh AIR context; the resulting
// per-function Air is appended to sema->func_air_list.
static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) {
uint32_t payload_index = sema->code.inst_datas[inst].pl_node.payload_index;
ZirInstTag tag = sema->code.inst_tags[inst];
bool is_fancy = (tag == ZIR_INST_FUNC_FANCY);
// Parse payload depending on variant.
// Func/FuncInferred: {ret_ty(u32), param_block(u32), body_len(u32)}
// FuncFancy: {param_block(u32), body_len(u32), bits(u32)}
uint32_t body_len;
uint32_t extra_index; // will point to body instructions
uint32_t ret_ty_body_len = 0;
uint32_t ret_ty_ref_pos = 0; // extra[] index of ret_ty ref (if len==1)
uint32_t param_block_pi; // payload offset of param_block field
if (is_fancy) {
// FuncFancy extra: {param_block, body_len, bits}
body_len = sema->code.extra[payload_index + 1];
uint32_t bits = sema->code.extra[payload_index + 2];
param_block_pi = 0; // param_block at payload_index + 0
// Skip trailing optional data after the 3-word header.
extra_index = payload_index + 3;
bool has_cc_body = (bits & (1u << 4)) != 0;
bool has_cc_ref = (bits & (1u << 3)) != 0;
bool has_ret_ty_body = (bits & (1u << 6)) != 0;
bool has_ret_ty_ref = (bits & (1u << 5)) != 0;
bool has_any_noalias = (bits & (1u << 7)) != 0;
if (has_cc_body) {
uint32_t cc_body_len = sema->code.extra[extra_index];
extra_index += 1 + cc_body_len;
} else if (has_cc_ref) {
extra_index += 1; // single ref
}
if (has_ret_ty_body) {
uint32_t rtb_len = sema->code.extra[extra_index];
ret_ty_body_len = rtb_len;
ret_ty_ref_pos = extra_index + 1;
extra_index += 1 + rtb_len;
} else if (has_ret_ty_ref) {
ret_ty_body_len = 1; // single ref
ret_ty_ref_pos = extra_index;
extra_index += 1;
}
if (has_any_noalias) {
extra_index += 1;
}
} else {
// Func/FuncInferred extra: {ret_ty(u32), param_block(u32),
// body_len(u32)}
uint32_t ret_ty_raw = sema->code.extra[payload_index];
body_len = sema->code.extra[payload_index + 2];
ret_ty_body_len = ret_ty_raw & 0x7FFFFFFF; // low 31 bits
param_block_pi = 1; // param_block at payload_index + 1
extra_index = payload_index + 3;
if (ret_ty_body_len >= 1) {
ret_ty_ref_pos = extra_index;
extra_index += ret_ty_body_len;
}
}
// extra_index now points to the body instructions.
bool has_body = (body_len != 0);
// Only analyze exported functions with bodies.
// A function is considered exported if either:
// 1. Its declaration has export linkage (cur_decl_is_export), or
// 2. It was referenced by an @export builtin (exported_decl_names).
bool is_exported = sema->cur_decl_is_export;
if (!is_exported) {
for (uint32_t e = 0; e < sema->num_exported_decl_names; e++) {
if (s_exported_decl_names[e] == sema->cur_decl_name) {
is_exported = true;
break;
}
}
}
if (!has_body || !is_exported || !sema->func_air_list)
// analyzeFuncBodyAndRecord: analyze a function body in fresh AIR context
// and append the per-function Air to sema->func_air_list.
// Ported from the body analysis portion of zirFunc.
// Used for both exported functions (from zirFunc) and non-inline callees
// (from zirCall). name_idx is a string_bytes index for the function name.
static void analyzeFuncBodyAndRecord(
Sema* sema, SemaBlock* block, uint32_t func_inst, uint32_t name_idx) {
if (!sema->func_air_list)
return;
FuncZirInfo fi = parseFuncZir(sema, func_inst);
if (fi.body_len == 0)
return;
uint32_t payload_index
= sema->code.inst_datas[func_inst].pl_node.payload_index;
// Resolve multi-instruction return type body BEFORE saving state,
// so that the parent scope's inst_map and AIR arrays are available.
// Ported from src/Sema.zig zirFunc: resolveGenericBody(block,
// ret_ty_body).
// Deduplication: skip if already analyzed.
if (name_idx != 0) {
const char* name_str = (const char*)&sema->code.string_bytes[name_idx];
SemaFuncAirList* list = sema->func_air_list;
for (uint32_t i = 0; i < list->len; i++) {
if (list->items[i].name
&& strcmp(list->items[i].name + 5, name_str) == 0)
return; // +5 to skip "root." prefix
}
}
// Resolve multi-instruction return type body BEFORE saving state.
TypeIndex pre_resolved_ret_ty = TYPE_NONE;
if (ret_ty_body_len > 2) {
const uint32_t* ret_ty_body = &sema->code.extra[ret_ty_ref_pos];
(void)analyzeBodyInner(sema, block, ret_ty_body, ret_ty_body_len);
if (fi.ret_ty_body_len > 2) {
const uint32_t* ret_ty_body = &sema->code.extra[fi.ret_ty_ref_pos];
(void)analyzeBodyInner(sema, block, ret_ty_body, fi.ret_ty_body_len);
ZirInstRef operand = sema->code.inst_datas[sema->comptime_break_inst]
.break_data.operand;
AirInstRef ret_air = resolveInst(sema, operand);
@@ -5006,24 +4943,18 @@ static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) {
sema->num_type_fn_to_skip = 0;
sema->num_memo = 0;
// Reserve extra[0] for main_block index (Air.ExtraIndex.main_block).
// Reserve extra[0] for main_block index.
semaAddExtra(sema, 0);
// Resolve the function return type.
// Ported from src/Sema.zig zirFunc (lines 8869-8885).
if (ret_ty_body_len == 0) {
if (fi.ret_ty_body_len == 0) {
sema->fn_ret_ty = IP_INDEX_VOID_TYPE;
} else if (ret_ty_body_len == 1) {
ZirInstRef ret_ty_ref = sema->code.extra[ret_ty_ref_pos];
// For pre-interned refs, the ZIR ref == IP index.
// For inst refs, resolve through inst_map.
} else if (fi.ret_ty_body_len == 1) {
ZirInstRef ret_ty_ref = sema->code.extra[fi.ret_ty_ref_pos];
AirInstRef ret_air = resolveInst(sema, ret_ty_ref);
sema->fn_ret_ty = AIR_REF_TO_IP(ret_air);
} else if (ret_ty_body_len == 2) {
// Two-instruction return type body: [ptr_type, break_inline].
uint32_t ret_body_start
= ret_ty_ref_pos; // set by both func and func_fancy paths
uint32_t first_inst = sema->code.extra[ret_body_start];
} else if (fi.ret_ty_body_len == 2) {
uint32_t first_inst = sema->code.extra[fi.ret_ty_ref_pos];
ZirInstTag first_tag = sema->code.inst_tags[first_inst];
if (first_tag == ZIR_INST_PTR_TYPE) {
uint8_t zir_flags
@@ -5047,27 +4978,23 @@ static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) {
sema->fn_ret_ty = IP_INDEX_VOID_TYPE;
}
} else {
// Multi-instruction return type body resolved before state save.
sema->fn_ret_ty = pre_resolved_ret_ty;
}
// --- Set up block for function body ---
SemaBlock fn_block;
semaBlockInit(&fn_block, sema, NULL);
fn_block.is_comptime = false; // function body is runtime
fn_block.is_comptime = false;
fn_block.want_safety = false;
fn_block.want_safety_set = true;
// --- Process parameters ---
// Ported from src/Zcu/PerThread.zig analyzeFnBodyInner (lines 2884-2940).
// Get param body from param_block, emit AIR arg instructions, and map
// param ZIR instructions to their corresponding AIR arg refs.
uint32_t param_block_inst
= sema->code.extra[payload_index + param_block_pi];
= sema->code.extra[payload_index + fi.param_block_pi];
const uint32_t* param_body;
uint32_t param_body_len;
getParamBody(sema, param_block_inst, &param_body, &param_body_len);
// Count param instructions in param body.
uint32_t total_params = 0;
for (uint32_t p = 0; p < param_body_len; p++) {
ZirInstTag ptag = sema->code.inst_tags[param_body[p]];
@@ -5076,12 +5003,9 @@ static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) {
|| ptag == ZIR_INST_PARAM_ANYTYPE_COMPTIME)
total_params++;
}
if (total_params > 0) {
if (total_params > 0)
instMapEnsureSpaceForBody(&sema->inst_map, param_body, param_body_len);
}
// Emit arg AIR instructions for each runtime parameter.
uint32_t runtime_param_index = 0;
for (uint32_t p = 0; p < param_body_len; p++) {
uint32_t param_inst = param_body[p];
@@ -5091,18 +5015,12 @@ static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) {
&& ptag != ZIR_INST_PARAM_ANYTYPE_COMPTIME)
continue;
// Read param extra: {name(u32), type_packed(u32)}.
// Ported from lib/std/zig/Zir.zig Inst.Param.
uint32_t param_payload
= sema->code.inst_datas[param_inst].pl_tok.payload_index;
uint32_t type_packed = sema->code.extra[param_payload + 1];
uint32_t type_body_len_p = type_packed & 0x7FFFFFFF;
// Resolve param type from type body.
// For simple (non-generic) types, the type body contains a single
// break_inline instruction whose operand is the type ref.
// For pointer types, the type body is [ptr_type, break_inline].
TypeIndex param_ty = IP_INDEX_VOID_TYPE; // fallback
TypeIndex param_ty = IP_INDEX_VOID_TYPE;
if (type_body_len_p == 1) {
uint32_t type_inst = sema->code.extra[param_payload + 2];
ZirInstTag type_tag = sema->code.inst_tags[type_inst];
@@ -5115,21 +5033,17 @@ static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) {
uint32_t first_inst = sema->code.extra[param_payload + 2];
ZirInstTag first_tag = sema->code.inst_tags[first_inst];
if (first_tag == ZIR_INST_PTR_TYPE) {
// ptr_type: flags(u8) + size(u8) + pad(u16) + payload_index
uint8_t zir_flags
= sema->code.inst_datas[first_inst].ptr_type.flags;
uint8_t zir_size
= sema->code.inst_datas[first_inst].ptr_type.size;
uint32_t pi
= sema->code.inst_datas[first_inst].ptr_type.payload_index;
ZirInstRef elem_ty_ref
= sema->code.extra[pi]; // PtrType.elem_type
ZirInstRef elem_ty_ref = sema->code.extra[pi];
AirInstRef elem_air = resolveInst(sema, elem_ty_ref);
TypeIndex elem_ty = AIR_REF_TO_IP(elem_air);
// Build IP PtrType key.
uint32_t ip_flags = (uint32_t)zir_size & PTR_FLAGS_SIZE_MASK;
if (!(zir_flags
& 0x02)) // ZIR bit 1 = is_mutable; !is_mutable → const
if (!(zir_flags & 0x02))
ip_flags |= PTR_FLAGS_IS_CONST;
InternPoolKey key;
memset(&key, 0, sizeof(key));
@@ -5139,10 +5053,6 @@ static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) {
param_ty = ipIntern(sema->ip, key);
}
} else if (type_body_len_p > 2) {
// Multi-instruction param type body (e.g. F16T(f64) call).
// Ported from src/Sema.zig zirParam: resolveInlineBody(block,
// body, inst). Evaluate the type body at comptime — no
// runtime AIR instructions should be emitted.
const uint32_t* type_body = &sema->code.extra[param_payload + 2];
instMapEnsureSpaceForBody(
&sema->inst_map, type_body, type_body_len_p);
@@ -5157,41 +5067,31 @@ static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) {
param_ty = AIR_REF_TO_IP(type_air);
}
// Emit AIR_INST_ARG.
AirInstData arg_data;
memset(&arg_data, 0, sizeof(arg_data));
arg_data.arg.ty_ref = AIR_REF_FROM_IP(param_ty);
arg_data.arg.zir_param_index = runtime_param_index;
AirInstRef arg_ref = semaAddInst(&fn_block, AIR_INST_ARG, arg_data);
// Map param ZIR inst → arg AIR ref.
instMapPut(&sema->inst_map, param_inst, arg_ref);
runtime_param_index++;
}
// Analyze the function body.
const uint32_t* body = &sema->code.extra[extra_index];
(void)analyzeBodyInner(sema, &fn_block, body, body_len);
const uint32_t* body = &sema->code.extra[fi.extra_index];
(void)analyzeBodyInner(sema, &fn_block, body, fi.body_len);
// --- Write main block to extra ---
// Layout: AirBlock{body_len}, then body_len instruction indices.
uint32_t main_block_extra = semaAddExtra(sema, fn_block.instructions_len);
for (uint32_t i = 0; i < fn_block.instructions_len; i++) {
for (uint32_t i = 0; i < fn_block.instructions_len; i++)
semaAddExtra(sema, fn_block.instructions[i]);
}
// Patch extra[0] = main_block index.
sema->air_extra[0] = main_block_extra;
semaBlockDeinit(&fn_block);
// --- Build function name ---
// Use the declaration name from sema->cur_decl_name (string_bytes index).
char* func_name = NULL;
if (sema->cur_decl_name != 0) {
const char* name_ptr
= (const char*)&sema->code.string_bytes[sema->cur_decl_name];
if (name_idx != 0) {
const char* name_ptr = (const char*)&sema->code.string_bytes[name_idx];
size_t name_len = strlen(name_ptr);
// Prefix with "root." to match the Zig FQN format.
size_t fqn_len = 5 + name_len; // "root." + name
func_name = malloc(fqn_len + 1);
if (func_name) {
@@ -5237,6 +5137,33 @@ static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) {
sema->num_calls = saved_num_calls;
}
// zirFunc: analyze a function declaration.
// Ported from src/Sema.zig zirFunc / zirFuncFancy / analyzeFnBodyInner.
// Handles ZIR_INST_FUNC, ZIR_INST_FUNC_INFERRED, and ZIR_INST_FUNC_FANCY.
// For the bootstrap, we only fully analyze exported functions with bodies.
// The function body is analyzed in a fresh AIR context; the resulting
// per-function Air is appended to sema->func_air_list.
static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) {
// Only analyze exported functions with bodies.
FuncZirInfo fi = parseFuncZir(sema, inst);
if (fi.body_len == 0 || !sema->func_air_list)
return;
bool is_exported = sema->cur_decl_is_export;
if (!is_exported) {
for (uint32_t e = 0; e < sema->num_exported_decl_names; e++) {
if (s_exported_decl_names[e] == sema->cur_decl_name) {
is_exported = true;
break;
}
}
}
if (!is_exported)
return;
analyzeFuncBodyAndRecord(sema, block, inst, sema->cur_decl_name);
}
// zirStructDecl: process struct_decl extended instruction.
// Iterates over declarations and analyzes their value bodies.
// Ported from src/Sema.zig zirStructDecl (subset) and
@@ -5543,11 +5470,7 @@ static AirInstRef semaResolveSwitchComptime(
for (uint32_t ci = 0; ci < copy_len; ci++) {
if (block->instructions_len >= block->instructions_cap) {
uint32_t new_cap = block->instructions_cap * 2;
block->instructions = realloc(
block->instructions, new_cap * sizeof(uint32_t));
if (!block->instructions)
exit(1);
block->instructions_cap = new_cap;
semaBlockGrowInstructions(block, new_cap);
}
block->instructions[block->instructions_len++]
= child_block.instructions[ci];
@@ -5613,11 +5536,7 @@ static AirInstRef semaResolveSwitchComptime(
for (uint32_t ci = 0; ci < copy_len; ci++) {
if (block->instructions_len >= block->instructions_cap) {
uint32_t new_cap = block->instructions_cap * 2;
block->instructions
= realloc(block->instructions, new_cap * sizeof(uint32_t));
if (!block->instructions)
exit(1);
block->instructions_cap = new_cap;
semaBlockGrowInstructions(block, new_cap);
}
block->instructions[block->instructions_len++]
= child_block.instructions[ci];
@@ -5768,9 +5687,9 @@ static InternPoolIndex ensureF80StructRegistered(Sema* sema) {
info->struct_type = struct_ip;
info->ptr_type = ptr_ip;
info->num_fields = 2;
info->fields[0].name = dupString("fraction");
info->fields[0].name = "fraction";
info->fields[0].type = IP_INDEX_U64_TYPE;
info->fields[1].name = dupString("exp");
info->fields[1].name = "exp";
info->fields[1].type = IP_INDEX_U16_TYPE;
return struct_ip;
}
@@ -6558,11 +6477,7 @@ static bool zirBlockInline(Sema* sema, SemaBlock* block, uint32_t inst) {
block->instructions_len = block_index;
if (block->instructions_len >= block->instructions_cap) {
uint32_t new_cap = block->instructions_cap * 2;
block->instructions
= realloc(block->instructions, new_cap * sizeof(uint32_t));
if (!block->instructions)
exit(1);
block->instructions_cap = new_cap;
semaBlockGrowInstructions(block, new_cap);
}
block->instructions[block->instructions_len++] = blk_inst;
}
@@ -6940,11 +6855,7 @@ static bool zirBlock(Sema* sema, SemaBlock* block, uint32_t inst) {
for (uint32_t ci = 0; ci < child_block.instructions_len; ci++) {
if (block->instructions_len >= block->instructions_cap) {
uint32_t new_cap = block->instructions_cap * 2;
block->instructions
= realloc(block->instructions, new_cap * sizeof(uint32_t));
if (!block->instructions)
exit(1);
block->instructions_cap = new_cap;
semaBlockGrowInstructions(block, new_cap);
}
block->instructions[block->instructions_len++]
= child_block.instructions[ci];
@@ -6974,11 +6885,7 @@ static bool zirBlock(Sema* sema, SemaBlock* block, uint32_t inst) {
block->instructions_len = block_index;
if (block->instructions_len >= block->instructions_cap) {
uint32_t new_cap = block->instructions_cap * 2;
block->instructions
= realloc(block->instructions, new_cap * sizeof(uint32_t));
if (!block->instructions)
exit(1);
block->instructions_cap = new_cap;
semaBlockGrowInstructions(block, new_cap);
}
block->instructions[block->instructions_len++] = blk_inst;
}
@@ -7047,22 +6954,14 @@ static bool zirBlock(Sema* sema, SemaBlock* block, uint32_t inst) {
sema->air_inst_datas[block_inst_idx].ty_pl.payload = extra_start;
if (block->instructions_len >= block->instructions_cap) {
uint32_t new_cap = block->instructions_cap * 2;
block->instructions
= realloc(block->instructions, new_cap * sizeof(uint32_t));
if (!block->instructions)
exit(1);
block->instructions_cap = new_cap;
semaBlockGrowInstructions(block, new_cap);
}
block->instructions[block->instructions_len++] = block_inst_idx;
} else {
for (uint32_t ci = 0; ci < child_block.instructions_len; ci++) {
if (block->instructions_len >= block->instructions_cap) {
uint32_t new_cap = block->instructions_cap * 2;
block->instructions = realloc(
block->instructions, new_cap * sizeof(uint32_t));
if (!block->instructions)
exit(1);
block->instructions_cap = new_cap;
semaBlockGrowInstructions(block, new_cap);
}
block->instructions[block->instructions_len++]
= child_block.instructions[ci];
@@ -7098,11 +6997,7 @@ static bool zirBlock(Sema* sema, SemaBlock* block, uint32_t inst) {
for (uint32_t ci = 0; ci < child_block.instructions_len; ci++) {
if (block->instructions_len >= block->instructions_cap) {
uint32_t new_cap = block->instructions_cap * 2;
block->instructions
= realloc(block->instructions, new_cap * sizeof(uint32_t));
if (!block->instructions)
exit(1);
block->instructions_cap = new_cap;
semaBlockGrowInstructions(block, new_cap);
}
block->instructions[block->instructions_len++]
= child_block.instructions[ci];
@@ -7121,11 +7016,7 @@ static bool zirBlock(Sema* sema, SemaBlock* block, uint32_t inst) {
for (uint32_t ci = 0; ci < last_inst_idx; ci++) {
if (block->instructions_len >= block->instructions_cap) {
uint32_t new_cap = block->instructions_cap * 2;
block->instructions = realloc(
block->instructions, new_cap * sizeof(uint32_t));
if (!block->instructions)
exit(1);
block->instructions_cap = new_cap;
semaBlockGrowInstructions(block, new_cap);
}
block->instructions[block->instructions_len++]
= child_block.instructions[ci];
@@ -7134,11 +7025,7 @@ static bool zirBlock(Sema* sema, SemaBlock* block, uint32_t inst) {
} else {
if (block->instructions_len >= block->instructions_cap) {
uint32_t new_cap = block->instructions_cap * 2;
block->instructions
= realloc(block->instructions, new_cap * sizeof(uint32_t));
if (!block->instructions)
exit(1);
block->instructions_cap = new_cap;
semaBlockGrowInstructions(block, new_cap);
}
block->instructions[block->instructions_len++] = block_inst_idx;
@@ -7157,11 +7044,7 @@ static bool zirBlock(Sema* sema, SemaBlock* block, uint32_t inst) {
} else {
if (block->instructions_len >= block->instructions_cap) {
uint32_t new_cap = block->instructions_cap * 2;
block->instructions
= realloc(block->instructions, new_cap * sizeof(uint32_t));
if (!block->instructions)
exit(1);
block->instructions_cap = new_cap;
semaBlockGrowInstructions(block, new_cap);
}
block->instructions[block->instructions_len++] = block_inst_idx;
@@ -7379,11 +7262,7 @@ static AirInstRef zirBoolBr(Sema* sema, SemaBlock* block, uint32_t inst) {
// Resolve the block.
if (block->instructions_len >= block->instructions_cap) {
uint32_t new_cap = block->instructions_cap * 2;
block->instructions
= realloc(block->instructions, new_cap * sizeof(uint32_t));
if (!block->instructions)
exit(1);
block->instructions_cap = new_cap;
semaBlockGrowInstructions(block, new_cap);
}
block->instructions[block->instructions_len++] = block_inst_idx;

View File

@@ -59,13 +59,17 @@ typedef struct SemaBlockInlining {
// --- SemaBlock ---
// Context for semantically analyzing ZIR instructions within a block.
#define SEMA_BLOCK_INITIAL_CAP 64
typedef struct SemaBlock {
struct SemaBlock* parent;
struct Sema* sema;
uint32_t namespace_index;
uint32_t* instructions;
uint32_t inline_instructions[SEMA_BLOCK_INITIAL_CAP];
uint32_t* instructions; // points to inline_instructions or heap
uint32_t instructions_len;
uint32_t instructions_cap;
bool instructions_on_heap;
SemaBlockLabel* label;
SemaBlockInlining* inlining;
uint32_t runtime_index;