sema: port parameter handling for identity function
Port getParamBody (from Zir.zig) and parameter processing in zirFunc (from PerThread.zig analyzeFnBodyInner) to handle function parameters. For each param, resolves the type from the param's type body and emits AIR_INST_ARG instructions mapped to the param ZIR instructions. Also adds explicit handling for ZIR_INST_PARAM (mapped to void at module level) and ZIR_INST_RESTORE_ERR_RET_INDEX_FN_ENTRY (no-op in ReleaseFast) in analyzeBodyInner. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
143
stage0/sema.c
143
stage0/sema.c
@@ -313,6 +313,62 @@ static bool declIdIsExport(uint32_t id) {
|
||||
static bool analyzeBodyInner(
|
||||
Sema* sema, SemaBlock* block, const uint32_t* body, uint32_t body_len);
|
||||
|
||||
// getParamBody: extract param body from a param_block ZIR instruction.
|
||||
// Ported from lib/std/zig/Zir.zig getParamBody.
|
||||
// Sets *body_out and *body_len_out to the param body.
|
||||
static void getParamBody(Sema* sema, uint32_t param_block_inst,
|
||||
const uint32_t** body_out, uint32_t* body_len_out) {
|
||||
ZirInstTag ptag = sema->code.inst_tags[param_block_inst];
|
||||
if (ptag == ZIR_INST_BLOCK_INLINE || ptag == ZIR_INST_BLOCK
|
||||
|| ptag == ZIR_INST_BLOCK_COMPTIME) {
|
||||
uint32_t pl
|
||||
= sema->code.inst_datas[param_block_inst].pl_node.payload_index;
|
||||
*body_len_out = sema->code.extra[pl]; // Block.body_len
|
||||
*body_out = &sema->code.extra[pl + 1];
|
||||
return;
|
||||
}
|
||||
if (ptag == ZIR_INST_DECLARATION) {
|
||||
// Parse declaration to find value body.
|
||||
// Ported from lib/std/zig/Zir.zig getDeclaration.
|
||||
uint32_t payload
|
||||
= sema->code.inst_datas[param_block_inst].declaration.payload_index;
|
||||
uint32_t flags_1 = sema->code.extra[payload + 5];
|
||||
uint32_t id = (flags_1 >> 27) & 0x1F;
|
||||
uint32_t di = payload + 6;
|
||||
if (declIdHasName(id))
|
||||
di++;
|
||||
if (declIdHasLibName(id))
|
||||
di++;
|
||||
uint32_t type_body_len = 0;
|
||||
if (declIdHasTypeBody(id)) {
|
||||
type_body_len = sema->code.extra[di];
|
||||
di++;
|
||||
}
|
||||
uint32_t align_body_len = 0;
|
||||
uint32_t linksection_body_len = 0;
|
||||
uint32_t addrspace_body_len = 0;
|
||||
if (declIdHasSpecialBodies(id)) {
|
||||
align_body_len = sema->code.extra[di];
|
||||
linksection_body_len = sema->code.extra[di + 1];
|
||||
addrspace_body_len = sema->code.extra[di + 2];
|
||||
di += 3;
|
||||
}
|
||||
uint32_t value_body_len = 0;
|
||||
if (declIdHasValueBody(id)) {
|
||||
value_body_len = sema->code.extra[di];
|
||||
di++;
|
||||
}
|
||||
di += type_body_len + align_body_len + linksection_body_len
|
||||
+ addrspace_body_len;
|
||||
*body_len_out = value_body_len;
|
||||
*body_out = &sema->code.extra[di];
|
||||
return;
|
||||
}
|
||||
assert(0 && "unexpected param_block tag");
|
||||
*body_out = NULL;
|
||||
*body_len_out = 0;
|
||||
}
|
||||
|
||||
// coerceIntRef: coerce an integer AIR ref to a target type.
|
||||
// If the ref points to a comptime_int IP entry and the target type
|
||||
// is a concrete integer type, creates a new IP entry with that type.
|
||||
@@ -427,6 +483,74 @@ static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) {
|
||||
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 + 1];
|
||||
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]];
|
||||
if (ptag == ZIR_INST_PARAM || ptag == ZIR_INST_PARAM_COMPTIME
|
||||
|| ptag == ZIR_INST_PARAM_ANYTYPE
|
||||
|| ptag == ZIR_INST_PARAM_ANYTYPE_COMPTIME)
|
||||
total_params++;
|
||||
}
|
||||
|
||||
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];
|
||||
ZirInstTag ptag = sema->code.inst_tags[param_inst];
|
||||
if (ptag != ZIR_INST_PARAM && ptag != ZIR_INST_PARAM_COMPTIME
|
||||
&& ptag != ZIR_INST_PARAM_ANYTYPE
|
||||
&& 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.
|
||||
TypeIndex param_ty = IP_INDEX_VOID_TYPE; // fallback
|
||||
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];
|
||||
assert(type_tag == ZIR_INST_BREAK_INLINE);
|
||||
ZirInstRef type_ref
|
||||
= sema->code.inst_datas[type_inst].break_data.operand;
|
||||
assert(type_ref < ZIR_REF_START_INDEX); // pre-interned
|
||||
param_ty = type_ref;
|
||||
}
|
||||
|
||||
// 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
|
||||
= blockAddInst(&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);
|
||||
@@ -675,6 +799,25 @@ static bool analyzeBodyInner(
|
||||
i++;
|
||||
continue;
|
||||
|
||||
// param: parameter declaration (in comptime declaration body).
|
||||
// At module level, params are not analyzed; zirFunc processes
|
||||
// them separately. Map to void.
|
||||
case ZIR_INST_PARAM:
|
||||
case ZIR_INST_PARAM_COMPTIME:
|
||||
case ZIR_INST_PARAM_ANYTYPE:
|
||||
case ZIR_INST_PARAM_ANYTYPE_COMPTIME:
|
||||
instMapPut(
|
||||
&sema->inst_map, inst, AIR_REF_FROM_IP(IP_INDEX_VOID_TYPE));
|
||||
i++;
|
||||
continue;
|
||||
|
||||
// restore_err_ret_index_fn_entry: error return trace restore.
|
||||
// In ReleaseFast (no safety), this is a no-op.
|
||||
// Ported from src/Sema.zig zirRestoreErrRetIndex.
|
||||
case ZIR_INST_RESTORE_ERR_RET_INDEX_FN_ENTRY:
|
||||
i++;
|
||||
continue;
|
||||
|
||||
// int: intern a comptime integer literal.
|
||||
case ZIR_INST_INT:
|
||||
zirInt(sema, inst);
|
||||
|
||||
@@ -554,6 +554,6 @@ test "sema air: return integer" {
|
||||
}
|
||||
|
||||
test "sema air: identity function" {
|
||||
if (true) return error.SkipZigTest;
|
||||
//if (true) return error.SkipZigTest;
|
||||
try semaAirRawCheck("export fn f(x: u32) u32 { return x; }");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user