sema: fix C integer type coercion and unresolved Int type computation; enable 7 corpus tests
- Add cIntToRegularInt() to normalize C integer types (c_uint, c_int, etc.) to regular integer types (u32, i32, etc.) in peer type resolution, matching upstream's cmpNumeric behavior that computes dest type via intType() - Fix semaCoerce to emit BITCAST (not INTCAST) when coercing between C integer types and regular integer types with same ABI layout - Compute type result for unresolved Int/Log2Int/PowerOfTwoSignificandZ calls by resolving arguments directly from ZIR, instead of returning void_value - Add comptime folding for enum_literal equality, @intFromBool, and void/noreturn dbg_var filtering - Enable fixhfdi, fixhfsi, fixxfdi, fixxfsi, unordhf2, unordxf2, secp256k1/field Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -67,6 +67,9 @@ static uint32_t ipHashKey(const InternPoolKey* key) {
|
||||
case IP_KEY_TUPLE_TYPE:
|
||||
h = ipHashCombine(h, key->data.tuple_type);
|
||||
break;
|
||||
case IP_KEY_ENUM_LITERAL:
|
||||
h = ipHashCombine(h, key->data.enum_literal);
|
||||
break;
|
||||
default:
|
||||
/* For other tag types, just use the tag hash. */
|
||||
break;
|
||||
@@ -117,6 +120,8 @@ static bool ipKeysEqual(const InternPoolKey* a, const InternPoolKey* b) {
|
||||
&& a->data.int_val.is_negative == b->data.int_val.is_negative;
|
||||
case IP_KEY_TUPLE_TYPE:
|
||||
return a->data.tuple_type == b->data.tuple_type;
|
||||
case IP_KEY_ENUM_LITERAL:
|
||||
return a->data.enum_literal == b->data.enum_literal;
|
||||
default:
|
||||
/* Fallback: memcmp the entire data union. */
|
||||
return memcmp(&a->data, &b->data, sizeof(a->data)) == 0;
|
||||
|
||||
583
stage0/sema.c
583
stage0/sema.c
@@ -5,6 +5,16 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// Simple djb2 hash for enum literal names.
|
||||
static uint32_t simpleStringHash(const char* s) {
|
||||
uint32_t h = 5381;
|
||||
while (*s) {
|
||||
h = h * 33 + (uint8_t)*s;
|
||||
s++;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
#define SEMA_AIR_INITIAL_CAP 256
|
||||
#define SEMA_AIR_EXTRA_INITIAL_CAP 256
|
||||
#define SEMA_BLOCK_INITIAL_CAP 64
|
||||
@@ -352,7 +362,9 @@ static void zirDbgVar(
|
||||
TypeIndex val_ty = semaTypeOf(sema, operand);
|
||||
if (val_ty == IP_INDEX_TYPE_TYPE || val_ty == IP_INDEX_COMPTIME_INT_TYPE
|
||||
|| val_ty == IP_INDEX_COMPTIME_FLOAT_TYPE
|
||||
|| val_ty == IP_INDEX_ENUM_LITERAL_TYPE) {
|
||||
|| val_ty == IP_INDEX_ENUM_LITERAL_TYPE
|
||||
|| val_ty == IP_INDEX_VOID_TYPE
|
||||
|| val_ty == IP_INDEX_NORETURN_TYPE) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -594,6 +606,36 @@ static TypeIndex semaTypeOf(Sema* sema, AirInstRef ref) {
|
||||
}
|
||||
}
|
||||
|
||||
// cIntToRegularInt: normalize C integer types to regular integer types.
|
||||
// Ported from src/Sema.zig cmpNumeric which computes dest type via
|
||||
// intType(signedness, bits), producing regular int types (u32, i64, etc.)
|
||||
// instead of C integer types (c_uint, c_long, etc.).
|
||||
// Mapping is for x86-64 Linux (LP64 data model).
|
||||
static TypeIndex cIntToRegularInt(TypeIndex ty) {
|
||||
switch (ty) {
|
||||
case IP_INDEX_C_CHAR_TYPE:
|
||||
return IP_INDEX_I8_TYPE;
|
||||
case IP_INDEX_C_SHORT_TYPE:
|
||||
return IP_INDEX_I16_TYPE;
|
||||
case IP_INDEX_C_USHORT_TYPE:
|
||||
return IP_INDEX_U16_TYPE;
|
||||
case IP_INDEX_C_INT_TYPE:
|
||||
return IP_INDEX_I32_TYPE;
|
||||
case IP_INDEX_C_UINT_TYPE:
|
||||
return IP_INDEX_U32_TYPE;
|
||||
case IP_INDEX_C_LONG_TYPE:
|
||||
return IP_INDEX_I64_TYPE;
|
||||
case IP_INDEX_C_ULONG_TYPE:
|
||||
return IP_INDEX_U64_TYPE;
|
||||
case IP_INDEX_C_LONGLONG_TYPE:
|
||||
return IP_INDEX_I64_TYPE;
|
||||
case IP_INDEX_C_ULONGLONG_TYPE:
|
||||
return IP_INDEX_U64_TYPE;
|
||||
default:
|
||||
return ty;
|
||||
}
|
||||
}
|
||||
|
||||
// semaResolvePeerTypes: determine the common type of two AIR refs.
|
||||
// Ported from src/Sema.zig semaResolvePeerTypess (simplified).
|
||||
static TypeIndex semaResolvePeerTypes(
|
||||
@@ -603,9 +645,9 @@ static TypeIndex semaResolvePeerTypes(
|
||||
if (lhs_ty == rhs_ty)
|
||||
return lhs_ty;
|
||||
if (lhs_ty == IP_INDEX_COMPTIME_INT_TYPE)
|
||||
return rhs_ty;
|
||||
return cIntToRegularInt(rhs_ty);
|
||||
if (rhs_ty == IP_INDEX_COMPTIME_INT_TYPE)
|
||||
return lhs_ty;
|
||||
return cIntToRegularInt(lhs_ty);
|
||||
// When both types are concrete int types, pick the wider type.
|
||||
// Ported from src/Sema.zig peer_resolve_int_int (fixed_int strategy).
|
||||
if (sema->ip->items[lhs_ty].tag == IP_KEY_INT_TYPE
|
||||
@@ -621,6 +663,15 @@ static TypeIndex semaResolvePeerTypes(
|
||||
return lhs_ty;
|
||||
}
|
||||
|
||||
// isIntegerType: check if a type is an integer type (INT_TYPE or C int).
|
||||
// Returns true for IP_KEY_INT_TYPE and C integer SIMPLE_TYPEs.
|
||||
static bool isIntegerType(const InternPool* ip, TypeIndex ty) {
|
||||
if (ip->items[ty].tag == IP_KEY_INT_TYPE)
|
||||
return true;
|
||||
// C integer simple types (c_short..c_ulonglong).
|
||||
return ty >= IP_INDEX_C_CHAR_TYPE && ty <= IP_INDEX_C_ULONGLONG_TYPE;
|
||||
}
|
||||
|
||||
// semaCoerce: coerce an AIR ref to a target type.
|
||||
// Ported from src/Sema.zig coerce (simplified).
|
||||
static AirInstRef semaCoerce(
|
||||
@@ -640,18 +691,33 @@ static AirInstRef semaCoerce(
|
||||
return AIR_REF_FROM_IP(ipIntern(sema->ip, key));
|
||||
}
|
||||
// Comptime int→int coercion: re-intern with target type.
|
||||
if (AIR_REF_IS_IP(ref) && sema->ip->items[src_ty].tag == IP_KEY_INT_TYPE
|
||||
&& sema->ip->items[target_ty].tag == IP_KEY_INT_TYPE) {
|
||||
if (AIR_REF_IS_IP(ref) && isIntegerType(sema->ip, src_ty)
|
||||
&& isIntegerType(sema->ip, target_ty)) {
|
||||
return semaCoerceIntRef(sema, ref, target_ty);
|
||||
}
|
||||
// Runtime int→int coercion: emit intcast.
|
||||
if (AIR_REF_IS_INST(ref) && sema->ip->items[src_ty].tag == IP_KEY_INT_TYPE
|
||||
&& sema->ip->items[target_ty].tag == IP_KEY_INT_TYPE) {
|
||||
// Runtime int→int coercion: emit bitcast (same layout) or intcast.
|
||||
// Ported from src/Sema.zig coerceInMemoryAllowed / coerce.
|
||||
if (AIR_REF_IS_INST(ref) && isIntegerType(sema->ip, src_ty)
|
||||
&& isIntegerType(sema->ip, target_ty)) {
|
||||
// C integer simple types and regular int types with the same
|
||||
// ABI (same bits/signedness) are coerced via bitcast.
|
||||
// Different layout → intcast.
|
||||
AirInstTag tag = AIR_INST_BITCAST;
|
||||
if (sema->ip->items[src_ty].tag == IP_KEY_INT_TYPE
|
||||
&& sema->ip->items[target_ty].tag == IP_KEY_INT_TYPE) {
|
||||
InternPoolKey src_key = sema->ip->items[src_ty];
|
||||
InternPoolKey tgt_key = sema->ip->items[target_ty];
|
||||
if (src_key.data.int_type.bits != tgt_key.data.int_type.bits
|
||||
|| src_key.data.int_type.signedness
|
||||
!= tgt_key.data.int_type.signedness) {
|
||||
tag = AIR_INST_INTCAST;
|
||||
}
|
||||
}
|
||||
AirInstData data;
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.ty_op.ty_ref = AIR_REF_FROM_IP(target_ty);
|
||||
data.ty_op.operand = ref;
|
||||
return semaAddInst(block, AIR_INST_INTCAST, data);
|
||||
return semaAddInst(block, tag, data);
|
||||
}
|
||||
// For unsupported type combinations (e.g. type→void during comptime
|
||||
// analysis of generic functions), return the operand unchanged.
|
||||
@@ -821,10 +887,28 @@ static AirInstRef zirBoolNot(Sema* sema, SemaBlock* block, uint32_t inst) {
|
||||
|
||||
// zirIntFromBool: handle int_from_bool ZIR instruction (@intFromBool).
|
||||
// Ported from src/Sema.zig zirIntFromBool.
|
||||
// Emits AIR_INST_BITCAST to u1.
|
||||
// Comptime: resolve known bools to u1 integer.
|
||||
// Runtime: emits AIR_INST_BITCAST to u1.
|
||||
static AirInstRef zirIntFromBool(Sema* sema, SemaBlock* block, uint32_t inst) {
|
||||
ZirInstRef operand_ref = sema->code.inst_datas[inst].un_node.operand;
|
||||
AirInstRef operand = resolveInst(sema, operand_ref);
|
||||
// Comptime folding: known bools → u1 integer.
|
||||
if (operand == AIR_REF_FROM_IP(IP_INDEX_BOOL_TRUE)) {
|
||||
InternPoolKey key;
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.tag = IP_KEY_INT;
|
||||
key.data.int_val.ty = IP_INDEX_U1_TYPE;
|
||||
key.data.int_val.value_lo = 1;
|
||||
return AIR_REF_FROM_IP(ipIntern(sema->ip, key));
|
||||
}
|
||||
if (operand == AIR_REF_FROM_IP(IP_INDEX_BOOL_FALSE)) {
|
||||
InternPoolKey key;
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.tag = IP_KEY_INT;
|
||||
key.data.int_val.ty = IP_INDEX_U1_TYPE;
|
||||
key.data.int_val.value_lo = 0;
|
||||
return AIR_REF_FROM_IP(ipIntern(sema->ip, key));
|
||||
}
|
||||
AirInstData data;
|
||||
memset(&data, 0, sizeof(data));
|
||||
data.ty_op.ty_ref = AIR_REF_FROM_IP(IP_INDEX_U1_TYPE);
|
||||
@@ -1108,6 +1192,16 @@ static AirInstRef zirArithmetic(
|
||||
return internComptimeInt(sema, result_ty, r_lo, r_hi);
|
||||
}
|
||||
|
||||
// Comptime equality for non-integer IP values (e.g. enum_literal).
|
||||
if (AIR_REF_IS_IP(lhs) && AIR_REF_IS_IP(rhs)
|
||||
&& (air_tag == AIR_INST_CMP_EQ || air_tag == AIR_INST_CMP_NEQ)) {
|
||||
bool eq = (AIR_REF_TO_IP(lhs) == AIR_REF_TO_IP(rhs));
|
||||
return AIR_REF_FROM_IP(
|
||||
(eq == (air_tag == AIR_INST_CMP_EQ))
|
||||
? IP_INDEX_BOOL_TRUE
|
||||
: IP_INDEX_BOOL_FALSE);
|
||||
}
|
||||
|
||||
emit_runtime:;
|
||||
TypeIndex peer_ty = semaResolvePeerTypes(sema, lhs, rhs);
|
||||
lhs = semaCoerce(sema, block, peer_ty, lhs);
|
||||
@@ -1391,6 +1485,7 @@ static AirInstRef zirAsNode(Sema* sema, SemaBlock* block, uint32_t inst) {
|
||||
dest_ty = AIR_REF_TO_IP(resolved);
|
||||
}
|
||||
AirInstRef operand = resolveInst(sema, operand_ref);
|
||||
TypeIndex src_ty = semaTypeOf(sema, operand);
|
||||
return semaCoerce(sema, block, dest_ty, operand);
|
||||
}
|
||||
|
||||
@@ -2945,6 +3040,89 @@ static AirInstRef zirCall(
|
||||
|
||||
if (func_inst == UINT32_MAX) {
|
||||
// Can't resolve callee; return void (fallback).
|
||||
// For known type-returning functions (Int, Log2Int,
|
||||
// PowerOfTwoSignificandZ), create a dead BLOCK to match
|
||||
// upstream's AIR layout where every inline call creates
|
||||
// a block instruction, and compute the type result from args.
|
||||
if (callee_name_idx != 0) {
|
||||
const char* cn
|
||||
= (const char*)&sema->code.string_bytes[callee_name_idx];
|
||||
if (strcmp(cn, "Int") == 0 || strcmp(cn, "Log2Int") == 0
|
||||
|| strcmp(cn, "PowerOfTwoSignificandZ") == 0) {
|
||||
AirInstData dead;
|
||||
memset(&dead, 0, sizeof(dead));
|
||||
(void)semaAddInstAsIndex(sema, AIR_INST_BLOCK, dead);
|
||||
// Resolve args and compute the type result.
|
||||
// Same logic as the returns_type handler below.
|
||||
AirInstRef ur_arg_refs[16];
|
||||
uint32_t ur_prev_end = args_len;
|
||||
for (uint32_t a = 0; a < args_len && a < 16; a++) {
|
||||
uint32_t end_off
|
||||
= sema->code.extra[arg_data_start + a];
|
||||
uint32_t body_start = arg_data_start + ur_prev_end;
|
||||
uint32_t body_len = end_off - ur_prev_end;
|
||||
if (body_len > 1) {
|
||||
(void)analyzeBodyInner(sema, block,
|
||||
&sema->code.extra[body_start],
|
||||
body_len - 1);
|
||||
}
|
||||
if (body_len >= 1) {
|
||||
uint32_t li
|
||||
= sema->code.extra[body_start + body_len - 1];
|
||||
ZirInstRef op
|
||||
= sema->code.inst_datas[li].break_data.operand;
|
||||
ur_arg_refs[a] = resolveInst(sema, op);
|
||||
} else {
|
||||
ur_arg_refs[a]
|
||||
= AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
|
||||
}
|
||||
ur_prev_end = end_off;
|
||||
}
|
||||
InternPoolIndex ur_result = IP_INDEX_VOID_VALUE;
|
||||
if (strcmp(cn, "Int") == 0 && args_len >= 2) {
|
||||
uint8_t signedness = 0;
|
||||
uint16_t bits_val = 0;
|
||||
if (AIR_REF_IS_IP(ur_arg_refs[1])) {
|
||||
InternPoolKey k = ipIndexToKey(
|
||||
sema->ip, AIR_REF_TO_IP(ur_arg_refs[1]));
|
||||
if (k.tag == IP_KEY_INT)
|
||||
bits_val = (uint16_t)k.data.int_val.value_lo;
|
||||
}
|
||||
// Resolve signedness from enum_literal in arg 0.
|
||||
{
|
||||
uint32_t a0_end
|
||||
= sema->code.extra[arg_data_start + 0];
|
||||
uint32_t a0_start = arg_data_start + args_len;
|
||||
uint32_t a0_body_end = arg_data_start + a0_end;
|
||||
for (uint32_t ai = a0_start; ai < a0_body_end;
|
||||
ai++) {
|
||||
uint32_t zi = sema->code.extra[ai];
|
||||
if (zi < sema->code.inst_len
|
||||
&& sema->code.inst_tags[zi]
|
||||
== ZIR_INST_ENUM_LITERAL) {
|
||||
uint32_t si = sema->code.inst_datas[zi]
|
||||
.str_tok.start;
|
||||
const char* lit
|
||||
= (const char*)&sema->code
|
||||
.string_bytes[si];
|
||||
if (strcmp(lit, "signed") == 0)
|
||||
signedness = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bits_val > 0) {
|
||||
InternPoolKey ik;
|
||||
memset(&ik, 0, sizeof(ik));
|
||||
ik.tag = IP_KEY_INT_TYPE;
|
||||
ik.data.int_type.bits = bits_val;
|
||||
ik.data.int_type.signedness = signedness;
|
||||
ur_result = ipIntern(sema->ip, ik);
|
||||
}
|
||||
}
|
||||
return AIR_REF_FROM_IP(ur_result);
|
||||
}
|
||||
}
|
||||
return AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
|
||||
}
|
||||
|
||||
@@ -3094,7 +3272,7 @@ static AirInstRef zirCall(
|
||||
// need_debug_scope is always false → BLOCK tag.
|
||||
AirInstData rt_dead;
|
||||
memset(&rt_dead, 0, sizeof(rt_dead));
|
||||
uint32_t rt_idx = semaAddInstAsIndex(sema, AIR_INST_BLOCK, rt_dead);
|
||||
(void)semaAddInstAsIndex(sema, AIR_INST_BLOCK, rt_dead);
|
||||
InternPoolIndex result_type = IP_INDEX_NONE;
|
||||
|
||||
if (type_fn_name && strcmp(type_fn_name, "Int") == 0) {
|
||||
@@ -4427,6 +4605,35 @@ static AirInstRef semaResolveSwitchComptime(
|
||||
|
||||
(void)analyzeBodyInner(sema, &child_block, body, body_len);
|
||||
|
||||
// Ported from Sema.zig resolveAnalyzedBlock, 1-merge
|
||||
// case (line 6016-6024): if the trailing instruction
|
||||
// is a BR targeting our block, elide the block and
|
||||
// copy all instructions except the trailing BR to
|
||||
// the parent block.
|
||||
uint32_t copy_len = child_block.instructions_len;
|
||||
if (copy_len > 0) {
|
||||
uint32_t last = child_block.instructions
|
||||
[copy_len - 1];
|
||||
if (sema->air_inst_tags[last] == AIR_INST_BR
|
||||
&& sema->air_inst_datas[last].br.block_inst
|
||||
== block_inst)
|
||||
copy_len--;
|
||||
}
|
||||
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;
|
||||
}
|
||||
block->instructions[block->instructions_len++]
|
||||
= child_block.instructions[ci];
|
||||
}
|
||||
|
||||
AirInstRef result;
|
||||
if (label.merges.results_len > 0)
|
||||
result = label.merges.results[0];
|
||||
@@ -4475,6 +4682,31 @@ static AirInstRef semaResolveSwitchComptime(
|
||||
|
||||
(void)analyzeBodyInner(sema, &child_block, body, else_body_len);
|
||||
|
||||
// Ported from Sema.zig resolveAnalyzedBlock, 1-merge
|
||||
// case (line 6016-6024): elide trailing BR.
|
||||
uint32_t copy_len = child_block.instructions_len;
|
||||
if (copy_len > 0) {
|
||||
uint32_t last = child_block.instructions
|
||||
[copy_len - 1];
|
||||
if (sema->air_inst_tags[last] == AIR_INST_BR
|
||||
&& sema->air_inst_datas[last].br.block_inst
|
||||
== block_inst)
|
||||
copy_len--;
|
||||
}
|
||||
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;
|
||||
}
|
||||
block->instructions[block->instructions_len++]
|
||||
= child_block.instructions[ci];
|
||||
}
|
||||
|
||||
AirInstRef result;
|
||||
if (label.merges.results_len > 0)
|
||||
result = label.merges.results[0];
|
||||
@@ -4672,14 +4904,13 @@ static AirInstRef zirFieldValComptime(
|
||||
} else if (ct_tag == CT_TAG_INT_INFO
|
||||
&& strcmp(field_name, "signedness") == 0) {
|
||||
// Access .signedness on an int_info result.
|
||||
// Returns 0 for unsigned, 1 for signed.
|
||||
// Return an enum_literal matching std.builtin.Signedness.
|
||||
uint32_t s = (ct_val >> 16) & 0xFFFF;
|
||||
InternPoolKey key;
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.tag = IP_KEY_INT;
|
||||
key.data.int_val.ty = IP_INDEX_COMPTIME_INT_TYPE;
|
||||
key.data.int_val.value_lo = s;
|
||||
key.data.int_val.is_negative = false;
|
||||
key.tag = IP_KEY_ENUM_LITERAL;
|
||||
key.data.enum_literal
|
||||
= simpleStringHash(s ? "signed" : "unsigned");
|
||||
return AIR_REF_FROM_IP(ipIntern(sema->ip, key));
|
||||
}
|
||||
|
||||
@@ -5257,75 +5488,115 @@ static bool analyzeBodyInner(
|
||||
block->need_debug_scope = &need_debug_scope;
|
||||
uint32_t block_index = block->instructions_len;
|
||||
|
||||
// Save/restore comptime_break_inst to detect actual
|
||||
// break_inline vs terminal instruction.
|
||||
// Ported from src/Sema.zig block_inline ComptimeBreak
|
||||
// detection (line 1798-1811).
|
||||
uint32_t saved_cbi = sema->comptime_break_inst;
|
||||
sema->comptime_break_inst = UINT32_MAX;
|
||||
|
||||
bool completed
|
||||
= analyzeBodyInner(sema, block, inner_body, inner_body_len);
|
||||
|
||||
bool hit_comptime_break
|
||||
= (sema->comptime_break_inst != UINT32_MAX);
|
||||
|
||||
block->need_debug_scope = saved_need_debug_scope;
|
||||
|
||||
// If need_debug_scope was set, wrap instructions in a
|
||||
// BLOCK+BR for scoping. Ported from src/Sema.zig
|
||||
// ensurePostHoc: always creates a BLOCK when
|
||||
// need_debug_scope is true, even for empty bodies
|
||||
// (producing "phantom" BLOCKs matching upstream AIR).
|
||||
if (readBool(&need_debug_scope)) {
|
||||
uint32_t new_insts_count
|
||||
= block->instructions_len - block_index;
|
||||
|
||||
// Reserve an AIR block instruction.
|
||||
uint32_t blk_inst = semaAddInstAsIndex(sema, AIR_INST_BLOCK,
|
||||
(AirInstData) { .ty_pl = { .ty_ref = 0, .payload = 0 } });
|
||||
// Add a BR to exit the block with void_value.
|
||||
AirInstData br_data;
|
||||
memset(&br_data, 0, sizeof(br_data));
|
||||
br_data.br.block_inst = blk_inst;
|
||||
br_data.br.operand = AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
|
||||
uint32_t br_inst
|
||||
= semaAddInstAsIndex(sema, AIR_INST_BR, br_data);
|
||||
|
||||
// Write block extra: body_len2, then body insts.
|
||||
uint32_t body_len2 = new_insts_count + 1; // +1 for BR
|
||||
uint32_t extra_start = semaAddExtra(sema, body_len2);
|
||||
for (uint32_t ci = block_index; ci < block->instructions_len;
|
||||
ci++) {
|
||||
semaAddExtra(sema, block->instructions[ci]);
|
||||
if (!hit_comptime_break) {
|
||||
// Body completed normally or hit terminal instruction
|
||||
// with 0 merges. Propagate need_debug_scope to parent.
|
||||
// Ported from src/Sema.zig resolveAnalyzedBlock
|
||||
// 0-merge case (line 5985-5991).
|
||||
if (saved_need_debug_scope) {
|
||||
*saved_need_debug_scope = true;
|
||||
}
|
||||
} else {
|
||||
// Break inline with need_debug_scope: create
|
||||
// BLOCK+BR wrapper. Ported from src/Sema.zig
|
||||
// resolveAnalyzedBlock 1-merge comptime case
|
||||
// (line 6031-6058).
|
||||
uint32_t new_insts_count
|
||||
= block->instructions_len - block_index;
|
||||
|
||||
uint32_t blk_inst = semaAddInstAsIndex(sema,
|
||||
AIR_INST_BLOCK,
|
||||
(AirInstData) {
|
||||
.ty_pl = { .ty_ref = 0, .payload = 0 }
|
||||
});
|
||||
AirInstData br_data;
|
||||
memset(&br_data, 0, sizeof(br_data));
|
||||
br_data.br.block_inst = blk_inst;
|
||||
br_data.br.operand
|
||||
= AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
|
||||
uint32_t br_inst = semaAddInstAsIndex(sema,
|
||||
AIR_INST_BR, br_data);
|
||||
|
||||
uint32_t body_len2 = new_insts_count + 1;
|
||||
uint32_t extra_start
|
||||
= semaAddExtra(sema, body_len2);
|
||||
for (uint32_t ci = block_index;
|
||||
ci < block->instructions_len; ci++) {
|
||||
semaAddExtra(sema, block->instructions[ci]);
|
||||
}
|
||||
semaAddExtra(sema, br_inst);
|
||||
|
||||
sema->air_inst_datas[blk_inst].ty_pl.ty_ref
|
||||
= AIR_REF_FROM_IP(IP_INDEX_VOID_TYPE);
|
||||
sema->air_inst_datas[blk_inst].ty_pl.payload
|
||||
= extra_start;
|
||||
|
||||
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;
|
||||
}
|
||||
block->instructions[block->instructions_len++]
|
||||
= blk_inst;
|
||||
}
|
||||
semaAddExtra(sema, br_inst);
|
||||
|
||||
// Patch the BLOCK instruction data.
|
||||
sema->air_inst_datas[blk_inst].ty_pl.ty_ref
|
||||
= AIR_REF_FROM_IP(IP_INDEX_VOID_TYPE);
|
||||
sema->air_inst_datas[blk_inst].ty_pl.payload = extra_start;
|
||||
|
||||
// Replace the instructions in the parent block:
|
||||
// truncate back to block_index, add just the BLOCK.
|
||||
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;
|
||||
}
|
||||
block->instructions[block->instructions_len++] = blk_inst;
|
||||
}
|
||||
|
||||
if (!completed) {
|
||||
// The inner body terminated with a break_inline.
|
||||
// The break_inline's operand is the result of this
|
||||
// block.
|
||||
if (hit_comptime_break) {
|
||||
// break_inline occurred. Check if it targets this
|
||||
// block or an outer one.
|
||||
// Ported from src/Sema.zig block_inline (line 1856-1862).
|
||||
uint32_t break_inst_zir = sema->comptime_break_inst;
|
||||
ZirInstData break_data_zir
|
||||
= sema->code.inst_datas[break_inst_zir];
|
||||
uint32_t break_payload
|
||||
= break_data_zir.break_data.payload_index;
|
||||
uint32_t break_block_inst
|
||||
= sema->code.extra[break_payload];
|
||||
ZirInstRef operand = break_data_zir.break_data.operand;
|
||||
AirInstRef result;
|
||||
if (operand == ZIR_REF_NONE) {
|
||||
result = AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
|
||||
} else {
|
||||
result = resolveInst(sema, operand);
|
||||
}
|
||||
|
||||
instMapPut(&sema->inst_map, inst, result);
|
||||
if (break_block_inst == inst) {
|
||||
// Break targets this block_inline. Consume it.
|
||||
sema->comptime_break_inst = saved_cbi;
|
||||
AirInstRef result;
|
||||
if (operand == ZIR_REF_NONE) {
|
||||
result = AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
|
||||
} else {
|
||||
result = resolveInst(sema, operand);
|
||||
}
|
||||
instMapPut(&sema->inst_map, inst, result);
|
||||
} else {
|
||||
// Break targets outer block — propagate.
|
||||
// comptime_break_inst already set.
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// No break occurred. Restore comptime_break_inst.
|
||||
sema->comptime_break_inst = saved_cbi;
|
||||
}
|
||||
i++;
|
||||
continue;
|
||||
@@ -5465,6 +5736,39 @@ static bool analyzeBodyInner(
|
||||
i++;
|
||||
continue;
|
||||
|
||||
// @min / @max: comptime min/max of two values.
|
||||
// Ported from src/Sema.zig zirMinMax.
|
||||
case ZIR_INST_MIN:
|
||||
case ZIR_INST_MAX: {
|
||||
bool is_max = (sema->code.inst_tags[inst] == ZIR_INST_MAX);
|
||||
uint32_t pl
|
||||
= sema->code.inst_datas[inst].pl_node.payload_index;
|
||||
ZirInstRef zir_lhs = sema->code.extra[pl];
|
||||
ZirInstRef zir_rhs = sema->code.extra[pl + 1];
|
||||
AirInstRef min_lhs = resolveInst(sema, zir_lhs);
|
||||
AirInstRef min_rhs = resolveInst(sema, zir_rhs);
|
||||
int64_t lv, rv;
|
||||
if (isComptimeInt(sema, min_lhs, &lv)
|
||||
&& isComptimeInt(sema, min_rhs, &rv)) {
|
||||
int64_t result_val = is_max ? (lv > rv ? lv : rv)
|
||||
: (lv < rv ? lv : rv);
|
||||
InternPoolKey key;
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.tag = IP_KEY_INT;
|
||||
key.data.int_val.ty = IP_INDEX_COMPTIME_INT_TYPE;
|
||||
key.data.int_val.value_lo
|
||||
= (uint64_t)(result_val < 0 ? -result_val : result_val);
|
||||
key.data.int_val.is_negative = (result_val < 0);
|
||||
instMapPut(&sema->inst_map, inst,
|
||||
AIR_REF_FROM_IP(ipIntern(sema->ip, key)));
|
||||
} else {
|
||||
instMapPut(&sema->inst_map, inst,
|
||||
AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE));
|
||||
}
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// @bitCast.
|
||||
case ZIR_INST_BITCAST:
|
||||
instMapPut(&sema->inst_map, inst, zirBitcast(sema, block, inst));
|
||||
@@ -5680,15 +5984,12 @@ static bool analyzeBodyInner(
|
||||
ct_block.is_typeof = true;
|
||||
ct_block.inlining = block->inlining;
|
||||
|
||||
uint32_t saved_air_len = sema->air_inst_len;
|
||||
uint32_t saved_extra_len = sema->air_extra_len;
|
||||
|
||||
// Upstream does NOT save/restore air_inst_len here.
|
||||
// AIR instructions created during typeof body are orphaned
|
||||
// but persist in the flat array (matching upstream behavior).
|
||||
bool completed = analyzeBodyInner(
|
||||
sema, &ct_block, inner_body, inner_body_len);
|
||||
|
||||
sema->air_inst_len = saved_air_len;
|
||||
sema->air_extra_len = saved_extra_len;
|
||||
|
||||
AirInstRef result;
|
||||
if (!completed) {
|
||||
uint32_t break_inst = sema->comptime_break_inst;
|
||||
@@ -5755,6 +6056,22 @@ static bool analyzeBodyInner(
|
||||
i++;
|
||||
continue;
|
||||
|
||||
// enum_literal: intern as IP_KEY_ENUM_LITERAL.
|
||||
// Ported from src/Sema.zig zirEnumLiteral.
|
||||
case ZIR_INST_ENUM_LITERAL: {
|
||||
uint32_t name_start = sema->code.inst_datas[inst].str_tok.start;
|
||||
const char* name
|
||||
= (const char*)&sema->code.string_bytes[name_start];
|
||||
InternPoolKey key;
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.tag = IP_KEY_ENUM_LITERAL;
|
||||
key.data.enum_literal = simpleStringHash(name);
|
||||
instMapPut(&sema->inst_map, inst,
|
||||
AIR_REF_FROM_IP(ipIntern(sema->ip, key)));
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// switch_block: comptime switch on a known value.
|
||||
case ZIR_INST_SWITCH_BLOCK:
|
||||
instMapPut(&sema->inst_map, inst,
|
||||
@@ -5989,15 +6306,10 @@ static bool analyzeBodyInner(
|
||||
uint32_t inner_body_len = sema->code.extra[payload_index];
|
||||
const uint32_t* inner_body = &sema->code.extra[payload_index + 1];
|
||||
|
||||
// Comptime block: handle inline (no AIR block allocated).
|
||||
// Ported from Sema.zig line 1719-1721: comptime .block
|
||||
// redirects to .block_inline, with need_debug_scope
|
||||
// tracking for correct lexical scoping.
|
||||
if (block->is_comptime) {
|
||||
SemaBlockLabel label;
|
||||
memset(&label, 0, sizeof(label));
|
||||
label.zir_block = inst;
|
||||
|
||||
// Track need_debug_scope for BLOCK wrapping.
|
||||
bool need_debug_scope = false;
|
||||
bool* saved_need_debug_scope = block->need_debug_scope;
|
||||
@@ -6120,11 +6432,104 @@ static bool analyzeBodyInner(
|
||||
bool need_debug_scope = false;
|
||||
child_block.need_debug_scope = &need_debug_scope;
|
||||
|
||||
uint32_t saved_comptime_break = sema->comptime_break_inst;
|
||||
sema->comptime_break_inst = UINT32_MAX;
|
||||
bool body_completed = analyzeBodyInner(
|
||||
sema, &child_block, inner_body, inner_body_len);
|
||||
bool is_comptime_break = (sema->comptime_break_inst != UINT32_MAX);
|
||||
if (!is_comptime_break)
|
||||
sema->comptime_break_inst = saved_comptime_break;
|
||||
|
||||
// Resolve the block: write extra data and patch type.
|
||||
// Ported from src/Sema.zig resolveAnalyzedBlock.
|
||||
// Ported from src/Sema.zig resolveBlockBody / resolveAnalyzedBlock.
|
||||
|
||||
// Handle ComptimeBreak: a break_inline was encountered in
|
||||
// the body. Ported from Sema.zig resolveBlockBody line 5915.
|
||||
if (is_comptime_break && label.merges.results_len == 0) {
|
||||
// Copy child instructions to parent block.
|
||||
if (need_debug_scope
|
||||
&& child_block.instructions_len > 0) {
|
||||
// Wrap in BLOCK for scoping.
|
||||
AirInstData br_data;
|
||||
memset(&br_data, 0, sizeof(br_data));
|
||||
br_data.br.block_inst = block_inst_idx;
|
||||
br_data.br.operand
|
||||
= AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
|
||||
uint32_t br_inst = semaAddInstAsIndex(
|
||||
sema, AIR_INST_BR, br_data);
|
||||
uint32_t body_len2
|
||||
= child_block.instructions_len + 1;
|
||||
uint32_t extra_start
|
||||
= semaAddExtra(sema, body_len2);
|
||||
for (uint32_t ci = 0;
|
||||
ci < child_block.instructions_len; ci++) {
|
||||
semaAddExtra(
|
||||
sema, child_block.instructions[ci]);
|
||||
}
|
||||
semaAddExtra(sema, br_inst);
|
||||
sema->air_inst_datas[block_inst_idx].ty_pl.ty_ref
|
||||
= AIR_REF_FROM_IP(IP_INDEX_VOID_TYPE);
|
||||
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;
|
||||
}
|
||||
block->instructions[block->instructions_len++]
|
||||
= block_inst_idx;
|
||||
} else {
|
||||
// Copy instructions directly to parent.
|
||||
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;
|
||||
}
|
||||
block->instructions[block->instructions_len++]
|
||||
= child_block.instructions[ci];
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the comptime break targets this block.
|
||||
uint32_t break_inst = sema->comptime_break_inst;
|
||||
ZirInstData bdata2 = sema->code.inst_datas[break_inst];
|
||||
uint32_t break_block_inst
|
||||
= sema->code.extra[bdata2.break_data.payload_index + 1];
|
||||
|
||||
if (break_block_inst == inst) {
|
||||
// Break targets this block: resolve operand.
|
||||
AirInstRef ct_result = resolveInst(
|
||||
sema, bdata2.break_data.operand);
|
||||
sema->comptime_break_inst = saved_comptime_break;
|
||||
free(label.merges.results);
|
||||
free(label.merges.br_list);
|
||||
semaBlockDeinit(&child_block);
|
||||
instMapPut(&sema->inst_map, inst, ct_result);
|
||||
i++;
|
||||
continue;
|
||||
} else {
|
||||
// Break targets outer block: propagate.
|
||||
free(label.merges.results);
|
||||
free(label.merges.br_list);
|
||||
semaBlockDeinit(&child_block);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
(void)body_completed;
|
||||
AirInstRef block_result;
|
||||
if (label.merges.results_len == 0) {
|
||||
@@ -6701,6 +7106,22 @@ static bool analyzeBodyInner(
|
||||
continue;
|
||||
}
|
||||
|
||||
// int_type: create an integer type from signedness and bit count.
|
||||
// Ported from src/Sema.zig zirIntType.
|
||||
case ZIR_INST_INT_TYPE: {
|
||||
uint8_t signedness = sema->code.inst_datas[inst].int_type.signedness;
|
||||
uint16_t bit_count = sema->code.inst_datas[inst].int_type.bit_count;
|
||||
InternPoolKey key;
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.tag = IP_KEY_INT_TYPE;
|
||||
key.data.int_type.bits = bit_count;
|
||||
key.data.int_type.signedness = signedness;
|
||||
instMapPut(&sema->inst_map, inst,
|
||||
AIR_REF_FROM_IP(ipIntern(sema->ip, key)));
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// For all other instructions, produce a void mapping and skip.
|
||||
// As handlers are implemented, they will replace this default.
|
||||
default: {
|
||||
|
||||
@@ -125,13 +125,13 @@ const corpus_files = .{
|
||||
"../lib/compiler_rt/truncxfdf2.zig", // 333
|
||||
"../lib/compiler_rt/truncxfsf2.zig", // 333
|
||||
"../lib/std/crypto/pcurves/p256/field.zig", // 338
|
||||
//"../lib/compiler_rt/fixhfdi.zig", // 341
|
||||
//"../lib/compiler_rt/fixhfsi.zig", // 341
|
||||
//"../lib/compiler_rt/fixxfdi.zig", // 341
|
||||
//"../lib/compiler_rt/fixxfsi.zig", // 341
|
||||
//"../lib/compiler_rt/unordhf2.zig", // 341
|
||||
//"../lib/compiler_rt/unordxf2.zig", // 341
|
||||
//"../lib/std/crypto/pcurves/secp256k1/field.zig", // 343
|
||||
"../lib/compiler_rt/fixhfdi.zig", // 341
|
||||
"../lib/compiler_rt/fixhfsi.zig", // 341
|
||||
"../lib/compiler_rt/fixxfdi.zig", // 341
|
||||
"../lib/compiler_rt/fixxfsi.zig", // 341
|
||||
"../lib/compiler_rt/unordhf2.zig", // 341
|
||||
"../lib/compiler_rt/unordxf2.zig", // 341
|
||||
"../lib/std/crypto/pcurves/secp256k1/field.zig", // 343
|
||||
//"../lib/compiler_rt/divhf3.zig", // 344
|
||||
//"../lib/compiler_rt/floatdihf.zig", // 347
|
||||
//"../lib/compiler_rt/floatdixf.zig", // 347
|
||||
|
||||
Reference in New Issue
Block a user