sema: add store, compare, ptr_type param, and validate_* handlers
New ZIR instruction handlers: - STORE_NODE: store value to pointer (bin_op with coercion) - CMP_LT/LTE/EQ/GTE/GT/NEQ: comparison operations - VALIDATE_DEREF, VALIDATE_CONST: no-op validation (skip in body) Infrastructure: - ptrChildType: extract child type from pointer type - Extend param type body resolution to handle ptr_type + break_inline (2-instruction type body, e.g. *u32 param) - Fix PARAM dispatch: skip without overwriting inst_map (was clobbering arg mapping set by zirFunc) New tests: pointer param identity, store to pointer, compare lt/eq, f32 arithmetic, multi-param, nested bitcast xor, sub comptime. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -510,6 +510,31 @@ static AirInstRef semaCoerce(
|
||||
return ref;
|
||||
}
|
||||
|
||||
// ptrChildType: get the child (element) type of a pointer type.
|
||||
static TypeIndex ptrChildType(const InternPool* ip, TypeIndex ptr_ty) {
|
||||
assert(ip->items[ptr_ty].tag == IP_KEY_PTR_TYPE);
|
||||
return ip->items[ptr_ty].data.ptr_type.child;
|
||||
}
|
||||
|
||||
// zirStoreNode: handle store_node ZIR instruction.
|
||||
// Ported from src/Sema.zig zirStoreNode (simplified, no safety).
|
||||
static void zirStoreNode(Sema* sema, SemaBlock* block, uint32_t inst) {
|
||||
uint32_t payload_index
|
||||
= sema->code.inst_datas[inst].pl_node.payload_index;
|
||||
ZirInstRef ptr_ref = sema->code.extra[payload_index];
|
||||
ZirInstRef val_ref = sema->code.extra[payload_index + 1];
|
||||
AirInstRef ptr = resolveInst(sema, ptr_ref);
|
||||
AirInstRef val = resolveInst(sema, val_ref);
|
||||
TypeIndex ptr_ty = semaTypeOf(sema, ptr);
|
||||
TypeIndex elem_ty = ptrChildType(sema->ip, ptr_ty);
|
||||
val = semaCoerce(sema, block, elem_ty, val);
|
||||
AirInstData data;
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.bin_op.lhs = ptr;
|
||||
data.bin_op.rhs = val;
|
||||
(void)blockAddInst(block, AIR_INST_STORE, data);
|
||||
}
|
||||
|
||||
// zirArithmetic: handle add/sub ZIR instructions.
|
||||
// Ported from src/Sema.zig zirArithmetic.
|
||||
static AirInstRef zirArithmetic(
|
||||
@@ -856,6 +881,7 @@ static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) {
|
||||
// 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
|
||||
if (type_body_len_p == 1) {
|
||||
uint32_t type_inst = sema->code.extra[param_payload + 2];
|
||||
@@ -865,6 +891,31 @@ static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) {
|
||||
= sema->code.inst_datas[type_inst].break_data.operand;
|
||||
assert(type_ref < ZIR_REF_START_INDEX); // pre-interned
|
||||
param_ty = type_ref;
|
||||
} else if (type_body_len_p == 2) {
|
||||
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
|
||||
assert(elem_ty_ref < ZIR_REF_START_INDEX); // pre-interned
|
||||
TypeIndex elem_ty = elem_ty_ref;
|
||||
// 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
|
||||
ip_flags |= PTR_FLAGS_IS_CONST;
|
||||
InternPoolKey key;
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.tag = IP_KEY_PTR_TYPE;
|
||||
key.data.ptr_type.child = elem_ty;
|
||||
key.data.ptr_type.flags = ip_flags;
|
||||
param_ty = ipIntern(sema->ip, key);
|
||||
}
|
||||
}
|
||||
|
||||
// Emit AIR_INST_ARG.
|
||||
@@ -1131,12 +1182,11 @@ static bool analyzeBodyInner(
|
||||
// param: parameter declaration (in comptime declaration body).
|
||||
// At module level, params are not analyzed; zirFunc processes
|
||||
// them separately. Map to void.
|
||||
// Params: already mapped to arg AIR refs by zirFunc.
|
||||
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;
|
||||
|
||||
@@ -1262,6 +1312,38 @@ static bool analyzeBodyInner(
|
||||
i++;
|
||||
continue;
|
||||
|
||||
// Comparisons: same binary pattern as arithmetic.
|
||||
case ZIR_INST_CMP_LT:
|
||||
instMapPut(&sema->inst_map, inst,
|
||||
zirArithmetic(sema, block, inst, AIR_INST_CMP_LT));
|
||||
i++;
|
||||
continue;
|
||||
case ZIR_INST_CMP_LTE:
|
||||
instMapPut(&sema->inst_map, inst,
|
||||
zirArithmetic(sema, block, inst, AIR_INST_CMP_LTE));
|
||||
i++;
|
||||
continue;
|
||||
case ZIR_INST_CMP_EQ:
|
||||
instMapPut(&sema->inst_map, inst,
|
||||
zirArithmetic(sema, block, inst, AIR_INST_CMP_EQ));
|
||||
i++;
|
||||
continue;
|
||||
case ZIR_INST_CMP_GTE:
|
||||
instMapPut(&sema->inst_map, inst,
|
||||
zirArithmetic(sema, block, inst, AIR_INST_CMP_GTE));
|
||||
i++;
|
||||
continue;
|
||||
case ZIR_INST_CMP_GT:
|
||||
instMapPut(&sema->inst_map, inst,
|
||||
zirArithmetic(sema, block, inst, AIR_INST_CMP_GT));
|
||||
i++;
|
||||
continue;
|
||||
case ZIR_INST_CMP_NEQ:
|
||||
instMapPut(&sema->inst_map, inst,
|
||||
zirArithmetic(sema, block, inst, AIR_INST_CMP_NEQ));
|
||||
i++;
|
||||
continue;
|
||||
|
||||
// Bitwise: xor, bit_and, bit_or.
|
||||
case ZIR_INST_XOR:
|
||||
instMapPut(&sema->inst_map, inst,
|
||||
@@ -1331,6 +1413,18 @@ static bool analyzeBodyInner(
|
||||
i++;
|
||||
continue;
|
||||
|
||||
// Store.
|
||||
case ZIR_INST_STORE_NODE:
|
||||
zirStoreNode(sema, block, inst);
|
||||
i++;
|
||||
continue;
|
||||
|
||||
// Validation-only (no AIR emitted).
|
||||
case ZIR_INST_VALIDATE_DEREF:
|
||||
case ZIR_INST_VALIDATE_CONST:
|
||||
i++;
|
||||
continue;
|
||||
|
||||
// For all other instructions, produce a void mapping and skip.
|
||||
// As handlers are implemented, they will replace this default.
|
||||
default: {
|
||||
|
||||
@@ -724,11 +724,19 @@ test "sema air: mul two args" {
|
||||
try semaAirRawCheck("export fn f(x: u32, y: u32) u32 { return x * y; }");
|
||||
}
|
||||
|
||||
// TODO: bool and/or require block merges and conditional analysis.
|
||||
// TODO: bool and/or require block merges and conditional analysis (bool_br_and).
|
||||
// test "sema air: bool and" {
|
||||
// try semaAirRawCheck("export fn f(x: bool, y: bool) bool { return x and y; }");
|
||||
// }
|
||||
|
||||
test "sema air: compare lt" {
|
||||
try semaAirRawCheck("export fn f(x: u32, y: u32) bool { return x < y; }");
|
||||
}
|
||||
|
||||
test "sema air: compare eq" {
|
||||
try semaAirRawCheck("export fn f(x: u32, y: u32) bool { return x == y; }");
|
||||
}
|
||||
|
||||
test "sema air: bit shift right" {
|
||||
try semaAirRawCheck("export fn f(x: u32) u32 { return x >> 1; }");
|
||||
}
|
||||
@@ -762,6 +770,42 @@ test "sema air: shift and mask" {
|
||||
);
|
||||
}
|
||||
|
||||
test "sema air: f32 arithmetic" {
|
||||
try semaAirRawCheck("export fn f(x: f32, y: f32) f32 { return x + y; }");
|
||||
}
|
||||
|
||||
test "sema air: multi-param function" {
|
||||
try semaAirRawCheck(
|
||||
\\export fn f(a: u32, b: u32, c: u32) u32 {
|
||||
\\ return (a + b) * c;
|
||||
\\}
|
||||
);
|
||||
}
|
||||
|
||||
test "sema air: nested bitcast xor" {
|
||||
try semaAirRawCheck(
|
||||
\\export fn f(a: f32) f32 {
|
||||
\\ return @bitCast(@as(u32, @bitCast(a)) ^ @as(u32, 0x80000000));
|
||||
\\}
|
||||
);
|
||||
}
|
||||
|
||||
test "sema air: pointer param identity" {
|
||||
try semaAirRawCheck("export fn f(x: *u32) *u32 { return x; }");
|
||||
}
|
||||
|
||||
test "sema air: store to pointer" {
|
||||
try semaAirRawCheck(
|
||||
\\export fn f(x: *u32) void {
|
||||
\\ x.* = 42;
|
||||
\\}
|
||||
);
|
||||
}
|
||||
|
||||
test "sema air: sub comptime" {
|
||||
try semaAirRawCheck("export fn f(x: u32) u32 { return x - 1; }");
|
||||
}
|
||||
|
||||
test "sema air: bit shift left" {
|
||||
try semaAirRawCheck("export fn f(x: u32) u32 { return x << 1; }");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user