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:
@@ -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",
|
||||
|
||||
383
stage0/sema.c
383
stage0/sema.c
@@ -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, ¶m_body, ¶m_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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user