commit 040a65cf435f65f97b298211838c0ac2628cfa54 (tree)
parent e255742c1d8cb1a898a92046fcd6a1d89f5630d5
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date: Sat, 21 Feb 2026 18:13:17 +0000
sema: coerce BR operands in multi-merge blocks, enable addhf3
Add BR operand coercion in the multi-merge path of resolveAnalyzedBlock,
ported from Sema.zig lines 6125-6140. When a runtime block has multiple
breaks with different types (e.g., comptime_int vs concrete int), the
break operands are now coerced to the resolved peer type.
This fixes the AIR mismatch for addhf3.zig where `if (...) @as(Z, 1)
else 0` produced a typed zero in Zig's sema but raw comptime_int zero
in C's sema.
Also removes all debug fprintf traces from sema.c and debug prints
from sema_test.zig.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat:
4 files changed, 759 insertions(+), 692 deletions(-)
diff --git a/stage0/sema.c b/stage0/sema.c
@@ -138,8 +138,8 @@ static void instMapPut(InstMap* map, uint32_t zir_inst, AirInstRef ref) {
#define CT_TAG_INT_INFO 3
#define CT_TAG_REIFY_INT 4
-static void ctTrack(Sema* sema, InternPoolIndex ip_idx,
- uint8_t tag_val, uint32_t val) {
+static void ctTrack(
+ Sema* sema, InternPoolIndex ip_idx, uint8_t tag_val, uint32_t val) {
if (sema->ct_len < 16) {
sema->ct_keys[sema->ct_len] = ip_idx;
sema->ct_tags[sema->ct_len] = tag_val;
@@ -148,8 +148,8 @@ static void ctTrack(Sema* sema, InternPoolIndex ip_idx,
}
}
-static uint8_t ctLookup(const Sema* sema, InternPoolIndex ip_idx,
- uint32_t* val_out) {
+static uint8_t ctLookup(
+ const Sema* sema, InternPoolIndex ip_idx, uint32_t* val_out) {
for (uint32_t i = 0; i < sema->ct_len; i++) {
if (sema->ct_keys[i] == ip_idx) {
*val_out = sema->ct_vals[i];
@@ -344,8 +344,7 @@ static void zirDbgVar(
// Ported from src/Sema.zig addDbgVar: comptimeOnlySema /
// hasRuntimeBitsSema checks.
TypeIndex val_ty = semaTypeOf(sema, operand);
- if (val_ty == IP_INDEX_TYPE_TYPE
- || val_ty == IP_INDEX_COMPTIME_INT_TYPE
+ 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) {
return;
@@ -359,8 +358,7 @@ static void zirDbgVar(
if (block->need_debug_scope)
*block->need_debug_scope = true;
- const char* name
- = (const char*)&sema->code.string_bytes[str_idx];
+ const char* name = (const char*)&sema->code.string_bytes[str_idx];
uint32_t name_nts = semaAppendAirString(sema, name);
AirInstData data;
@@ -430,8 +428,7 @@ static bool declIdIsExport(uint32_t id) {
static bool analyzeBodyInner(
Sema* sema, SemaBlock* block, const uint32_t* body, uint32_t body_len);
static uint8_t analyzeBodyRuntimeBreak(
- Sema* sema, SemaBlock* block,
- const uint32_t* body, uint32_t body_len);
+ 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.
@@ -586,8 +583,7 @@ static TypeIndex semaTypeOf(Sema* sema, AirInstRef ref) {
// resolvePeerType: determine the common type of two AIR refs.
// Ported from src/Sema.zig resolvePeerTypes (simplified).
-static TypeIndex resolvePeerType(
- Sema* sema, AirInstRef lhs, AirInstRef rhs) {
+static TypeIndex resolvePeerType(Sema* sema, AirInstRef lhs, AirInstRef rhs) {
TypeIndex lhs_ty = semaTypeOf(sema, lhs);
TypeIndex rhs_ty = semaTypeOf(sema, rhs);
if (lhs_ty == rhs_ty)
@@ -602,8 +598,10 @@ static TypeIndex resolvePeerType(
// Ported from src/Sema.zig resolvePeerTypes peer_resolve_int_int.
if (sema->ip->items[lhs_ty].tag == IP_KEY_INT_TYPE
&& sema->ip->items[rhs_ty].tag == IP_KEY_INT_TYPE) {
- if (AIR_REF_IS_IP(lhs)) return rhs_ty;
- if (AIR_REF_IS_IP(rhs)) return lhs_ty;
+ if (AIR_REF_IS_IP(lhs))
+ return rhs_ty;
+ if (AIR_REF_IS_IP(rhs))
+ return lhs_ty;
}
// Unhandled combination (e.g. void×type in comptime analysis).
// Return lhs as fallback; this path doesn't produce runtime AIR.
@@ -620,14 +618,12 @@ static AirInstRef semaCoerce(
if (src_ty == IP_INDEX_COMPTIME_INT_TYPE)
return coerceIntRef(sema, ref, target_ty);
// 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
+ 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) {
return coerceIntRef(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
+ 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) {
AirInstData data;
memset(&data, 0, sizeof(data));
@@ -651,8 +647,7 @@ static TypeIndex ptrChildType(const InternPool* ip, TypeIndex ptr_ty) {
// 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;
+ 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);
@@ -765,8 +760,7 @@ static AirInstRef zirIntFromBool(Sema* sema, SemaBlock* block, uint32_t inst) {
// isComptimeInt: check if an AIR ref is a comptime integer value.
// Returns true and sets *value if the ref is a comptime int.
-static bool isComptimeInt(
- const Sema* sema, AirInstRef ref, int64_t* value) {
+static bool isComptimeInt(const Sema* sema, AirInstRef ref, int64_t* value) {
if (!AIR_REF_IS_IP(ref))
return false;
InternPoolIndex ip_idx = AIR_REF_TO_IP(ref);
@@ -783,8 +777,7 @@ static bool isComptimeInt(
}
// internComptimeInt: intern a comptime integer value with given type.
-static AirInstRef internComptimeInt(
- Sema* sema, TypeIndex ty, uint64_t value) {
+static AirInstRef internComptimeInt(Sema* sema, TypeIndex ty, uint64_t value) {
InternPoolKey key;
memset(&key, 0, sizeof(key));
key.tag = IP_KEY_INT;
@@ -797,7 +790,8 @@ static AirInstRef internComptimeInt(
// smallestUnsignedBits: compute the number of bits needed to represent max.
// Ported from src/Type.zig smallestUnsignedBits.
static uint16_t smallestUnsignedBits(uint16_t max) {
- if (max == 0) return 0;
+ if (max == 0)
+ return 0;
uint16_t count = 0;
uint16_t s = max;
while (s != 0) {
@@ -893,8 +887,7 @@ static AirInstRef zirByteSwap(Sema* sema, SemaBlock* block, uint32_t inst) {
// Ported from src/Sema.zig zirArithmetic.
static AirInstRef zirArithmetic(
Sema* sema, SemaBlock* block, uint32_t inst, AirInstTag air_tag) {
- uint32_t payload_index
- = sema->code.inst_datas[inst].pl_node.payload_index;
+ uint32_t payload_index = sema->code.inst_datas[inst].pl_node.payload_index;
ZirInstRef zir_lhs = sema->code.extra[payload_index];
ZirInstRef zir_rhs = sema->code.extra[payload_index + 1];
AirInstRef lhs = resolveInst(sema, zir_lhs);
@@ -909,10 +902,8 @@ static AirInstRef zirArithmetic(
int64_t result;
TypeIndex lhs_ty = semaTypeOf(sema, lhs);
TypeIndex rhs_ty = semaTypeOf(sema, rhs);
- TypeIndex result_ty = (lhs_ty == IP_INDEX_COMPTIME_INT_TYPE)
- ? rhs_ty : lhs_ty;
- if (result_ty == IP_INDEX_COMPTIME_INT_TYPE)
- result_ty = IP_INDEX_COMPTIME_INT_TYPE;
+ TypeIndex result_ty
+ = (lhs_ty == IP_INDEX_COMPTIME_INT_TYPE) ? rhs_ty : lhs_ty;
switch (air_tag) {
case AIR_INST_ADD:
case AIR_INST_ADD_WRAP:
@@ -928,28 +919,22 @@ static AirInstRef zirArithmetic(
break;
case AIR_INST_CMP_EQ:
return AIR_REF_FROM_IP(
- lhs_val == rhs_val
- ? IP_INDEX_BOOL_TRUE : IP_INDEX_BOOL_FALSE);
+ lhs_val == rhs_val ? IP_INDEX_BOOL_TRUE : IP_INDEX_BOOL_FALSE);
case AIR_INST_CMP_NEQ:
return AIR_REF_FROM_IP(
- lhs_val != rhs_val
- ? IP_INDEX_BOOL_TRUE : IP_INDEX_BOOL_FALSE);
+ lhs_val != rhs_val ? IP_INDEX_BOOL_TRUE : IP_INDEX_BOOL_FALSE);
case AIR_INST_CMP_LT:
return AIR_REF_FROM_IP(
- lhs_val < rhs_val
- ? IP_INDEX_BOOL_TRUE : IP_INDEX_BOOL_FALSE);
+ lhs_val < rhs_val ? IP_INDEX_BOOL_TRUE : IP_INDEX_BOOL_FALSE);
case AIR_INST_CMP_LTE:
return AIR_REF_FROM_IP(
- lhs_val <= rhs_val
- ? IP_INDEX_BOOL_TRUE : IP_INDEX_BOOL_FALSE);
+ lhs_val <= rhs_val ? IP_INDEX_BOOL_TRUE : IP_INDEX_BOOL_FALSE);
case AIR_INST_CMP_GT:
return AIR_REF_FROM_IP(
- lhs_val > rhs_val
- ? IP_INDEX_BOOL_TRUE : IP_INDEX_BOOL_FALSE);
+ lhs_val > rhs_val ? IP_INDEX_BOOL_TRUE : IP_INDEX_BOOL_FALSE);
case AIR_INST_CMP_GTE:
return AIR_REF_FROM_IP(
- lhs_val >= rhs_val
- ? IP_INDEX_BOOL_TRUE : IP_INDEX_BOOL_FALSE);
+ lhs_val >= rhs_val ? IP_INDEX_BOOL_TRUE : IP_INDEX_BOOL_FALSE);
default:
goto emit_runtime;
}
@@ -971,8 +956,7 @@ emit_runtime:;
// Ported from src/Sema.zig zirBitwise.
static AirInstRef zirBitwise(
Sema* sema, SemaBlock* block, uint32_t inst, AirInstTag air_tag) {
- uint32_t payload_index
- = sema->code.inst_datas[inst].pl_node.payload_index;
+ uint32_t payload_index = sema->code.inst_datas[inst].pl_node.payload_index;
ZirInstRef zir_lhs = sema->code.extra[payload_index];
ZirInstRef zir_rhs = sema->code.extra[payload_index + 1];
AirInstRef lhs = resolveInst(sema, zir_lhs);
@@ -986,10 +970,8 @@ static AirInstRef zirBitwise(
&& isComptimeInt(sema, rhs, &rhs_val)) {
TypeIndex lhs_ty = semaTypeOf(sema, lhs);
TypeIndex rhs_ty = semaTypeOf(sema, rhs);
- TypeIndex result_ty = (lhs_ty == IP_INDEX_COMPTIME_INT_TYPE)
- ? rhs_ty : lhs_ty;
- if (result_ty == IP_INDEX_COMPTIME_INT_TYPE)
- result_ty = IP_INDEX_COMPTIME_INT_TYPE;
+ TypeIndex result_ty
+ = (lhs_ty == IP_INDEX_COMPTIME_INT_TYPE) ? rhs_ty : lhs_ty;
uint64_t result;
switch (air_tag) {
case AIR_INST_XOR:
@@ -1021,8 +1003,7 @@ emit_bitwise_runtime:;
// zirBitcast: handle @bitCast ZIR instruction.
// Ported from src/Sema.zig zirBitcast.
static AirInstRef zirBitcast(Sema* sema, SemaBlock* block, uint32_t inst) {
- uint32_t payload_index
- = sema->code.inst_datas[inst].pl_node.payload_index;
+ uint32_t payload_index = sema->code.inst_datas[inst].pl_node.payload_index;
ZirInstRef dest_ty_ref = sema->code.extra[payload_index];
ZirInstRef operand_ref = sema->code.extra[payload_index + 1];
// Resolve destination type.
@@ -1054,8 +1035,7 @@ static AirInstRef zirBitcast(Sema* sema, SemaBlock* block, uint32_t inst) {
// Ported from src/Sema.zig zirIntCast / zirTruncate (simplified).
static AirInstRef zirTyOpCast(
Sema* sema, SemaBlock* block, uint32_t inst, AirInstTag air_tag) {
- uint32_t payload_index
- = sema->code.inst_datas[inst].pl_node.payload_index;
+ uint32_t payload_index = sema->code.inst_datas[inst].pl_node.payload_index;
ZirInstRef dest_ty_ref = sema->code.extra[payload_index];
ZirInstRef operand_ref = sema->code.extra[payload_index + 1];
AirInstRef dest_air = resolveInst(sema, dest_ty_ref);
@@ -1094,8 +1074,7 @@ static uint16_t floatBits(TypeIndex ty) {
// Ported from src/Sema.zig zirFloatCast.
// Emits FPEXT (widening) or FPTRUNC (narrowing).
static AirInstRef zirFloatCast(Sema* sema, SemaBlock* block, uint32_t inst) {
- uint32_t payload_index
- = sema->code.inst_datas[inst].pl_node.payload_index;
+ uint32_t payload_index = sema->code.inst_datas[inst].pl_node.payload_index;
ZirInstRef dest_ty_ref = sema->code.extra[payload_index];
ZirInstRef operand_ref = sema->code.extra[payload_index + 1];
AirInstRef dest_air = resolveInst(sema, dest_ty_ref);
@@ -1162,8 +1141,7 @@ static void zirTypeofLog2IntType(Sema* sema, uint32_t inst) {
// Ported from src/Sema.zig zirAsShiftOperand.
// Uses pl_node + As payload (dest_type, operand) — same layout as as_node.
static void zirAsShiftOperand(Sema* sema, SemaBlock* block, uint32_t inst) {
- uint32_t payload_index
- = sema->code.inst_datas[inst].pl_node.payload_index;
+ uint32_t payload_index = sema->code.inst_datas[inst].pl_node.payload_index;
ZirInstRef dest_ty_ref = sema->code.extra[payload_index];
ZirInstRef operand_ref = sema->code.extra[payload_index + 1];
// dest_ty comes from typeof_log2_int_type, which was mapped to an IP ref.
@@ -1180,8 +1158,7 @@ static void zirAsShiftOperand(Sema* sema, SemaBlock* block, uint32_t inst) {
// Ported from src/Sema.zig zirShl (simplified, runtime path only).
static AirInstRef zirShl(
Sema* sema, SemaBlock* block, uint32_t inst, AirInstTag air_tag) {
- uint32_t payload_index
- = sema->code.inst_datas[inst].pl_node.payload_index;
+ uint32_t payload_index = sema->code.inst_datas[inst].pl_node.payload_index;
ZirInstRef lhs_ref = sema->code.extra[payload_index];
ZirInstRef rhs_ref = sema->code.extra[payload_index + 1];
AirInstRef lhs = resolveInst(sema, lhs_ref);
@@ -1194,7 +1171,9 @@ static AirInstRef zirShl(
&& isComptimeInt(sema, rhs, &rhs_val)) {
TypeIndex lhs_ty = semaTypeOf(sema, lhs);
uint64_t result;
- if (air_tag == AIR_INST_SHL) {
+ if ((uint64_t)rhs_val >= 64) {
+ result = 0;
+ } else if (air_tag == AIR_INST_SHL) {
result = (uint64_t)lhs_val << (uint32_t)rhs_val;
} else {
result = (uint64_t)lhs_val >> (uint32_t)rhs_val;
@@ -1211,10 +1190,8 @@ static AirInstRef zirShl(
// zirAsNode: handle @as ZIR instruction.
// Ported from src/Sema.zig zirAs / zirAsNode.
-static AirInstRef zirAsNode(
- Sema* sema, SemaBlock* block, uint32_t inst) {
- uint32_t payload_index
- = sema->code.inst_datas[inst].pl_node.payload_index;
+static AirInstRef zirAsNode(Sema* sema, SemaBlock* block, uint32_t inst) {
+ uint32_t payload_index = sema->code.inst_datas[inst].pl_node.payload_index;
ZirInstRef dest_ty_ref = sema->code.extra[payload_index];
ZirInstRef operand_ref = sema->code.extra[payload_index + 1];
TypeIndex dest_ty;
@@ -1261,8 +1238,7 @@ typedef struct {
// parseFuncZir: parse a func/func_fancy ZIR instruction into FuncZirInfo.
// Ported from the parsing portion of zirFunc.
static FuncZirInfo parseFuncZir(Sema* sema, uint32_t inst) {
- uint32_t payload_index
- = sema->code.inst_datas[inst].pl_node.payload_index;
+ uint32_t payload_index = sema->code.inst_datas[inst].pl_node.payload_index;
ZirInstTag tag = sema->code.inst_tags[inst];
FuncZirInfo info;
memset(&info, 0, sizeof(info));
@@ -1348,8 +1324,8 @@ static const char* findDeclImportPath(Sema* sema, uint32_t name_idx) {
for (uint32_t i = 0; i < value_body_len; i++) {
ZirInstTag itag = sema->code.inst_tags[value_body[i]];
if (itag == ZIR_INST_IMPORT) {
- uint32_t pl = sema->code.inst_datas[value_body[i]]
- .pl_tok.payload_index;
+ uint32_t pl
+ = sema->code.inst_datas[value_body[i]].pl_tok.payload_index;
// extra: {res_ty, path} where path is string_bytes index
uint32_t path_idx = sema->code.extra[pl + 1];
return (const char*)&sema->code.string_bytes[path_idx];
@@ -1387,25 +1363,21 @@ static bool findDeclImportFieldVal(Sema* sema, uint32_t name_idx,
for (uint32_t i = 0; i < value_body_len; i++) {
ZirInstTag itag = sema->code.inst_tags[value_body[i]];
if (itag == ZIR_INST_IMPORT) {
- uint32_t pl = sema->code.inst_datas[value_body[i]]
- .pl_tok.payload_index;
+ uint32_t pl
+ = sema->code.inst_datas[value_body[i]].pl_tok.payload_index;
uint32_t path_idx = sema->code.extra[pl + 1];
- import_path
- = (const char*)&sema->code.string_bytes[path_idx];
- } else if ((itag == ZIR_INST_DECL_VAL
- || itag == ZIR_INST_DECL_REF)
+ import_path = (const char*)&sema->code.string_bytes[path_idx];
+ } else if ((itag == ZIR_INST_DECL_VAL || itag == ZIR_INST_DECL_REF)
&& !import_path) {
// Resolve the decl to its import path recursively.
uint32_t ref_name_idx
- = sema->code.inst_datas[value_body[i]]
- .str_tok.start;
+ = sema->code.inst_datas[value_body[i]].str_tok.start;
import_path = findDeclImportPath(sema, ref_name_idx);
} else if (itag == ZIR_INST_FIELD_VAL && import_path) {
- uint32_t pl = sema->code.inst_datas[value_body[i]]
- .pl_node.payload_index;
+ uint32_t pl
+ = sema->code.inst_datas[value_body[i]].pl_node.payload_index;
uint32_t fn_start = sema->code.extra[pl + 1];
- field_name
- = (const char*)&sema->code.string_bytes[fn_start];
+ field_name = (const char*)&sema->code.string_bytes[fn_start];
}
}
if (import_path && field_name) {
@@ -1453,8 +1425,8 @@ static Zir loadImportZirFromPath(const char* full_path, Ast* out_ast) {
// (like "std") via module_root.
// Returns a Zir with inst_len > 0 on success; inst_len == 0 on failure.
// The caller must call zirDeinit and astDeinit on the returned structures.
-static Zir loadImportZir(const char* source_dir,
- const char* import_path, Ast* out_ast) {
+static Zir loadImportZir(
+ const char* source_dir, const char* import_path, Ast* out_ast) {
Zir empty_zir;
memset(&empty_zir, 0, sizeof(empty_zir));
@@ -1464,8 +1436,7 @@ static Zir loadImportZir(const char* source_dir,
rel += 2;
char full_path[1024];
- int n = snprintf(full_path, sizeof(full_path), "%s/%s",
- source_dir, rel);
+ int n = snprintf(full_path, sizeof(full_path), "%s/%s", source_dir, rel);
if (n < 0 || (size_t)n >= sizeof(full_path))
return empty_zir;
@@ -1475,8 +1446,8 @@ static Zir loadImportZir(const char* source_dir,
// findDeclImportPathInZir: find a declaration by name in a ZIR module and
// return its @import path. Like findDeclImportPath but works on a raw Zir*
// instead of using sema's decl table. Returns NULL if not found.
-static const char* findDeclImportPathInZir(const Zir* zir,
- const char* decl_name) {
+static const char* findDeclImportPathInZir(
+ const Zir* zir, const char* decl_name) {
if (zir->inst_len == 0)
return NULL;
if (zir->inst_tags[0] != ZIR_INST_EXTENDED)
@@ -1515,8 +1486,7 @@ static const char* findDeclImportPathInZir(const Zir* zir,
uint32_t di_inst = zir->extra[extra_index + d];
if (zir->inst_tags[di_inst] != ZIR_INST_DECLARATION)
continue;
- uint32_t payload
- = zir->inst_datas[di_inst].declaration.payload_index;
+ uint32_t payload = zir->inst_datas[di_inst].declaration.payload_index;
uint32_t flags_1 = zir->extra[payload + 5];
uint32_t id = (flags_1 >> 27) & 0x1F;
uint32_t di = payload + 6;
@@ -1527,8 +1497,7 @@ static const char* findDeclImportPathInZir(const Zir* zir,
}
if (name_idx == 0)
continue;
- const char* name
- = (const char*)&zir->string_bytes[name_idx];
+ const char* name = (const char*)&zir->string_bytes[name_idx];
if (strcmp(name, decl_name) != 0)
continue;
if (declIdHasLibName(id))
@@ -1557,8 +1526,8 @@ static const char* findDeclImportPathInZir(const Zir* zir,
const uint32_t* value_body = &zir->extra[di];
for (uint32_t v = 0; v < value_body_len; v++) {
if (zir->inst_tags[value_body[v]] == ZIR_INST_IMPORT) {
- uint32_t pl = zir->inst_datas[value_body[v]]
- .pl_tok.payload_index;
+ uint32_t pl
+ = zir->inst_datas[value_body[v]].pl_tok.payload_index;
uint32_t path_idx = zir->extra[pl + 1];
return (const char*)&zir->string_bytes[path_idx];
}
@@ -1571,8 +1540,7 @@ static const char* findDeclImportPathInZir(const Zir* zir,
// raw Zir instead of sema's decl table. Finds a declaration by name and
// checks if its value body matches: (import | decl_val) + field_val.
// Returns true and sets out_import_path and out_field_name on success.
-static bool findDeclImportFieldValInZir(const Zir* zir,
- const char* decl_name,
+static bool findDeclImportFieldValInZir(const Zir* zir, const char* decl_name,
const char** out_import_path, const char** out_field_name) {
if (zir->inst_len == 0)
return false;
@@ -1612,8 +1580,7 @@ static bool findDeclImportFieldValInZir(const Zir* zir,
uint32_t di_inst = zir->extra[extra_index + d];
if (zir->inst_tags[di_inst] != ZIR_INST_DECLARATION)
continue;
- uint32_t payload
- = zir->inst_datas[di_inst].declaration.payload_index;
+ uint32_t payload = zir->inst_datas[di_inst].declaration.payload_index;
uint32_t flags_1 = zir->extra[payload + 5];
uint32_t id = (flags_1 >> 27) & 0x1F;
uint32_t di = payload + 6;
@@ -1624,8 +1591,7 @@ static bool findDeclImportFieldValInZir(const Zir* zir,
}
if (name_idx == 0)
continue;
- const char* name
- = (const char*)&zir->string_bytes[name_idx];
+ const char* name = (const char*)&zir->string_bytes[name_idx];
if (strcmp(name, decl_name) != 0)
continue;
if (declIdHasLibName(id))
@@ -1649,8 +1615,8 @@ static bool findDeclImportFieldValInZir(const Zir* zir,
value_body_len = zir->extra[di];
di++;
}
- di += type_body_len + align_body_len
- + linksection_body_len + addrspace_body_len;
+ di += type_body_len + align_body_len + linksection_body_len
+ + addrspace_body_len;
const uint32_t* value_body = &zir->extra[di];
if (value_body_len < 2)
return false;
@@ -1660,26 +1626,22 @@ static bool findDeclImportFieldValInZir(const Zir* zir,
for (uint32_t v = 0; v < value_body_len; v++) {
ZirInstTag itag = zir->inst_tags[value_body[v]];
if (itag == ZIR_INST_IMPORT) {
- uint32_t pl = zir->inst_datas[value_body[v]]
- .pl_tok.payload_index;
+ uint32_t pl
+ = zir->inst_datas[value_body[v]].pl_tok.payload_index;
uint32_t path_idx = zir->extra[pl + 1];
- import_path
- = (const char*)&zir->string_bytes[path_idx];
- } else if ((itag == ZIR_INST_DECL_VAL
- || itag == ZIR_INST_DECL_REF)
+ import_path = (const char*)&zir->string_bytes[path_idx];
+ } else if ((itag == ZIR_INST_DECL_VAL || itag == ZIR_INST_DECL_REF)
&& !import_path) {
uint32_t ref_name_idx
= zir->inst_datas[value_body[v]].str_tok.start;
const char* ref_name
= (const char*)&zir->string_bytes[ref_name_idx];
- import_path
- = findDeclImportPathInZir(zir, ref_name);
+ import_path = findDeclImportPathInZir(zir, ref_name);
} else if (itag == ZIR_INST_FIELD_VAL && import_path) {
- uint32_t pl = zir->inst_datas[value_body[v]]
- .pl_node.payload_index;
+ uint32_t pl
+ = zir->inst_datas[value_body[v]].pl_node.payload_index;
uint32_t fn_start = zir->extra[pl + 1];
- field_name
- = (const char*)&zir->string_bytes[fn_start];
+ field_name = (const char*)&zir->string_bytes[fn_start];
}
}
if (import_path && field_name) {
@@ -1696,23 +1658,21 @@ static bool findDeclImportFieldValInZir(const Zir* zir,
// Given module_root, source_dir, and import_path, compute the directory
// containing the imported file. For non-relative imports like "std",
// resolves to <module_root>/lib/<name>.
-static void computeSourceDir(const char* module_root,
- const char* source_dir, const char* import_path,
- char* out_dir, size_t out_size) {
+static void computeSourceDir(const char* module_root, const char* source_dir,
+ const char* import_path, char* out_dir, size_t out_size) {
if (import_path[0] == '.' && import_path[1] == '/') {
// Relative import: source_dir + dirname(import_path)
const char* rel = import_path + 2;
const char* last_slash = strrchr(rel, '/');
if (last_slash) {
- snprintf(out_dir, out_size, "%s/%.*s",
- source_dir, (int)(last_slash - rel), rel);
+ snprintf(out_dir, out_size, "%s/%.*s", source_dir,
+ (int)(last_slash - rel), rel);
} else {
snprintf(out_dir, out_size, "%s", source_dir);
}
} else if (module_root) {
// Non-relative (e.g. "std") → <module_root>/lib/<name>
- snprintf(out_dir, out_size, "%s/lib/%s",
- module_root, import_path);
+ snprintf(out_dir, out_size, "%s/lib/%s", module_root, import_path);
} else {
snprintf(out_dir, out_size, "%s", source_dir);
}
@@ -1721,9 +1681,8 @@ static void computeSourceDir(const char* module_root,
// loadStdImportZir: load a non-relative import via the module root.
// For @import("std"), resolves to <module_root>/lib/std/std.zig.
// For @import("math.zig") from std dir, uses source_dir as usual.
-static Zir loadStdImportZir(const char* module_root,
- const char* source_dir, const char* import_path,
- Ast* out_ast) {
+static Zir loadStdImportZir(const char* module_root, const char* source_dir,
+ const char* import_path, Ast* out_ast) {
// First try relative to source_dir (normal case).
Zir zir = loadImportZir(source_dir, import_path, out_ast);
if (zir.inst_len > 0)
@@ -1732,11 +1691,12 @@ static Zir loadStdImportZir(const char* module_root,
if (!module_root)
return zir;
- // For bare module names like "std", try <module_root>/lib/<name>/<name>.zig
+ // For bare module names like "std", try
+ // <module_root>/lib/<name>/<name>.zig
if (import_path[0] != '.' && import_path[0] != '/') {
char full_path[1024];
- int n = snprintf(full_path, sizeof(full_path),
- "%s/lib/%s/%s.zig", module_root, import_path, import_path);
+ int n = snprintf(full_path, sizeof(full_path), "%s/lib/%s/%s.zig",
+ module_root, import_path, import_path);
if (n >= 0 && (size_t)n < sizeof(full_path)) {
zir = loadImportZirFromPath(full_path, out_ast);
if (zir.inst_len > 0)
@@ -1795,11 +1755,9 @@ static void populateDeclTableFromZir(Sema* sema, const Zir* zir) {
= zir->inst_datas[decl_inst].declaration.payload_index;
uint32_t flags_1 = zir->extra[payload + 5];
uint32_t id = (flags_1 >> 27) & 0x1F;
- uint32_t di = payload + 6;
uint32_t decl_name = 0;
if (declIdHasName(id)) {
- decl_name = zir->extra[di];
- di++;
+ decl_name = zir->extra[payload + 6];
}
if (decl_name != 0 && sema->num_decls < 64) {
sema->decl_names[sema->num_decls] = decl_name;
@@ -1907,8 +1865,7 @@ static uint32_t findFuncInstInZir(const Zir* zir, const char* func_name) {
// Compare name.
if (decl_name_idx == 0)
continue;
- const char* decl_name
- = (const char*)&zir->string_bytes[decl_name_idx];
+ const char* decl_name = (const char*)&zir->string_bytes[decl_name_idx];
if (strcmp(decl_name, func_name) != 0)
continue;
@@ -1922,8 +1879,7 @@ static uint32_t findFuncInstInZir(const Zir* zir, const char* func_name) {
const uint32_t* value_body = &zir->extra[di];
for (uint32_t v = 0; v < value_body_len; v++) {
ZirInstTag vtag = zir->inst_tags[value_body[v]];
- if (vtag == ZIR_INST_FUNC
- || vtag == ZIR_INST_FUNC_FANCY
+ if (vtag == ZIR_INST_FUNC || vtag == ZIR_INST_FUNC_FANCY
|| vtag == ZIR_INST_FUNC_INFERRED)
return value_body[v];
}
@@ -1938,20 +1894,19 @@ static uint32_t findFuncInstInZir(const Zir* zir, const char* func_name) {
// source_dir is the directory containing the module.
// On success, returns func_inst and may replace *zir/*ast with the target
// module (freeing the old ones). On failure, returns UINT32_MAX.
-static uint32_t findFuncInModuleZir(const char* source_dir,
- Zir* zir, Ast* ast, const char* func_name) {
+static uint32_t findFuncInModuleZir(
+ const char* source_dir, Zir* zir, Ast* ast, const char* func_name) {
uint32_t func_inst = findFuncInstInZir(zir, func_name);
if (func_inst != UINT32_MAX)
return func_inst;
// Try re-export resolution.
const char* reexport_import = NULL;
const char* reexport_field = NULL;
- if (!findDeclImportFieldValInZir(zir, func_name,
- &reexport_import, &reexport_field))
+ if (!findDeclImportFieldValInZir(
+ zir, func_name, &reexport_import, &reexport_field))
return UINT32_MAX;
Ast target_ast;
- Zir target_zir
- = loadImportZir(source_dir, reexport_import, &target_ast);
+ Zir target_zir = loadImportZir(source_dir, reexport_import, &target_ast);
if (target_zir.inst_len == 0)
return UINT32_MAX;
func_inst = findFuncInstInZir(&target_zir, reexport_field);
@@ -2021,12 +1976,11 @@ static TypeIndex resolveFuncRetType(Sema* sema, const FuncZirInfo* info) {
// Ported from src/Sema.zig zirCall / analyzeCall (inline-only subset).
// For inline functions from the same module, analyzes the function body
// in a child block and emits dbg_inline_block.
-static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
- bool is_field_call) {
+static AirInstRef zirCall(
+ Sema* sema, SemaBlock* block, uint32_t inst, bool is_field_call) {
if (sema->has_compile_errors)
return AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
- uint32_t payload_index
- = sema->code.inst_datas[inst].pl_node.payload_index;
+ uint32_t payload_index = sema->code.inst_datas[inst].pl_node.payload_index;
// Parse Call/FieldCall extra data.
uint32_t flags = sema->code.extra[payload_index];
@@ -2041,8 +1995,7 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
// obj_ptr should be a decl_ref/decl_val pointing to a module.
// We don't resolve cross-module calls; just find by field_name.
callee_ref = sema->code.extra[payload_index + 1]; // obj_ptr
- uint32_t field_name_start
- = sema->code.extra[payload_index + 2];
+ uint32_t field_name_start = sema->code.extra[payload_index + 2];
callee_name_idx = field_name_start;
arg_data_start = payload_index + 3;
} else {
@@ -2057,8 +2010,7 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
ZirInstTag callee_tag = sema->code.inst_tags[callee_inst];
if (callee_tag == ZIR_INST_DECL_VAL
|| callee_tag == ZIR_INST_DECL_REF) {
- callee_name_idx
- = sema->code.inst_datas[callee_inst].str_tok.start;
+ callee_name_idx = sema->code.inst_datas[callee_inst].str_tok.start;
}
}
@@ -2081,23 +2033,19 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
if (callee_ref >= ZIR_REF_START_INDEX) {
uint32_t callee_inst = callee_ref - ZIR_REF_START_INDEX;
ZirInstTag ctag = sema->code.inst_tags[callee_inst];
- if (ctag == ZIR_INST_DECL_REF
- || ctag == ZIR_INST_DECL_VAL)
- obj_name_idx = sema->code.inst_datas[callee_inst]
- .str_tok.start;
+ if (ctag == ZIR_INST_DECL_REF || ctag == ZIR_INST_DECL_VAL)
+ obj_name_idx
+ = sema->code.inst_datas[callee_inst].str_tok.start;
}
if (obj_name_idx != 0) {
- const char* import_path
- = findDeclImportPath(sema, obj_name_idx);
+ const char* import_path = findDeclImportPath(sema, obj_name_idx);
if (import_path) {
const char* field_name
- = (const char*)&sema->code
- .string_bytes[callee_name_idx];
+ = (const char*)&sema->code.string_bytes[callee_name_idx];
import_zir = loadImportZir(
sema->source_dir, import_path, &import_ast);
if (import_zir.inst_len > 0) {
- func_inst = findFuncInModuleZir(
- sema->source_dir,
+ func_inst = findFuncInModuleZir(sema->source_dir,
&import_zir, &import_ast, field_name);
if (func_inst != UINT32_MAX) {
// Swap to imported module's ZIR.
@@ -2114,12 +2062,11 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
// → "std" → @import("std") → load std.zig
// → "math" in std.zig → @import("math.zig")
// → load math.zig → find callee there
- if (!is_cross_module && obj_name_idx != 0) {
+ if (!is_cross_module) {
const char* chain_import = NULL;
const char* chain_field = NULL;
if (findDeclImportFieldVal(
- sema, obj_name_idx,
- &chain_import, &chain_field)
+ sema, obj_name_idx, &chain_import, &chain_field)
&& chain_field) {
// chain_import is the base import (possibly "std")
// chain_field is the field name in that import
@@ -2128,21 +2075,18 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
// it (which may itself be an @import).
Ast base_ast;
memset(&base_ast, 0, sizeof(base_ast));
- Zir base_zir = loadStdImportZir(
- sema->module_root, sema->source_dir,
- chain_import, &base_ast);
+ Zir base_zir = loadStdImportZir(sema->module_root,
+ sema->source_dir, chain_import, &base_ast);
if (base_zir.inst_len > 0) {
// Find chain_field in base module; if it's
// also an @import, follow it.
const char* sub_import
- = findDeclImportPathInZir(
- &base_zir, chain_field);
+ = findDeclImportPathInZir(&base_zir, chain_field);
if (sub_import) {
// Compute source_dir for the base import.
char base_dir[1024];
- computeSourceDir(
- sema->module_root, sema->source_dir,
- chain_import, base_dir,
+ computeSourceDir(sema->module_root,
+ sema->source_dir, chain_import, base_dir,
sizeof(base_dir));
import_zir = loadImportZir(
base_dir, sub_import, &import_ast);
@@ -2151,12 +2095,9 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
if (import_zir.inst_len > 0) {
const char* field_name
= (const char*)&sema->code
- .string_bytes
- [callee_name_idx];
- func_inst = findFuncInModuleZir(
- base_dir,
- &import_zir, &import_ast,
- field_name);
+ .string_bytes[callee_name_idx];
+ func_inst = findFuncInModuleZir(base_dir,
+ &import_zir, &import_ast, field_name);
if (func_inst != UINT32_MAX) {
saved_code = sema->code;
sema->code = import_zir;
@@ -2168,8 +2109,8 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
const char* field_name
= (const char*)&sema->code
.string_bytes[callee_name_idx];
- func_inst = findFuncInstInZir(
- &base_zir, field_name);
+ func_inst
+ = findFuncInstInZir(&base_zir, field_name);
if (func_inst != UINT32_MAX) {
saved_code = sema->code;
sema->code = base_zir;
@@ -2192,29 +2133,23 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
if (!is_cross_module && callee_ref >= ZIR_REF_START_INDEX) {
uint32_t ci = callee_ref - ZIR_REF_START_INDEX;
ZirInstTag ctag2 = sema->code.inst_tags[ci];
- if (ctag2 == ZIR_INST_FIELD_PTR
- || ctag2 == ZIR_INST_FIELD_VAL) {
- uint32_t pi = sema->code.inst_datas[ci]
- .pl_node.payload_index;
+ if (ctag2 == ZIR_INST_FIELD_PTR || ctag2 == ZIR_INST_FIELD_VAL) {
+ uint32_t pi = sema->code.inst_datas[ci].pl_node.payload_index;
uint32_t lhs_ref = sema->code.extra[pi];
uint32_t mid_str = sema->code.extra[pi + 1];
if (lhs_ref >= ZIR_REF_START_INDEX) {
uint32_t li = lhs_ref - ZIR_REF_START_INDEX;
ZirInstTag lt = sema->code.inst_tags[li];
- if (lt == ZIR_INST_DECL_REF
- || lt == ZIR_INST_DECL_VAL) {
+ if (lt == ZIR_INST_DECL_REF || lt == ZIR_INST_DECL_VAL) {
uint32_t base_name_idx
- = sema->code.inst_datas[li]
- .str_tok.start;
+ = sema->code.inst_datas[li].str_tok.start;
const char* base_import
- = findDeclImportPath(
- sema, base_name_idx);
+ = findDeclImportPath(sema, base_name_idx);
// Function name is the field in the
// outer field_val (e.g. "floatMantissaBits"
// from math.floatMantissaBits).
const char* fn_field
- = (const char*)&sema->code
- .string_bytes[mid_str];
+ = (const char*)&sema->code.string_bytes[mid_str];
// If the lhs is not a direct import,
// try alias resolution. E.g. for
@@ -2223,42 +2158,32 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
const char* alias_import = NULL;
const char* alias_field = NULL;
if (!base_import
- && findDeclImportFieldVal(
- sema, base_name_idx,
+ && findDeclImportFieldVal(sema, base_name_idx,
&alias_import, &alias_field)) {
// alias_import = std import path
// alias_field = "math"
// Load std module, find sub-module
Ast alias_ast;
memset(&alias_ast, 0, sizeof(alias_ast));
- Zir alias_zir = loadStdImportZir(
- sema->module_root, sema->source_dir,
- alias_import, &alias_ast);
+ Zir alias_zir = loadStdImportZir(sema->module_root,
+ sema->source_dir, alias_import, &alias_ast);
if (alias_zir.inst_len > 0) {
- const char* sub_path
- = findDeclImportPathInZir(
- &alias_zir, alias_field);
+ const char* sub_path = findDeclImportPathInZir(
+ &alias_zir, alias_field);
if (sub_path) {
char alias_dir[1024];
- computeSourceDir(
- sema->module_root,
- sema->source_dir,
- alias_import, alias_dir,
- sizeof(alias_dir));
+ computeSourceDir(sema->module_root,
+ sema->source_dir, alias_import,
+ alias_dir, sizeof(alias_dir));
import_zir = loadImportZir(
- alias_dir, sub_path,
- &import_ast);
+ alias_dir, sub_path, &import_ast);
zirDeinit(&alias_zir);
astDeinit(&alias_ast);
if (import_zir.inst_len > 0) {
- func_inst
- = findFuncInModuleZir(
- alias_dir,
- &import_zir,
- &import_ast,
- fn_field);
- if (func_inst
- != UINT32_MAX) {
+ func_inst = findFuncInModuleZir(
+ alias_dir, &import_zir,
+ &import_ast, fn_field);
+ if (func_inst != UINT32_MAX) {
saved_code = sema->code;
sema->code = import_zir;
is_cross_module = true;
@@ -2272,45 +2197,34 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
}
if (!is_cross_module && base_import) {
- const char* mid_field
- = fn_field;
+ const char* mid_field = fn_field;
Ast base_ast;
memset(&base_ast, 0, sizeof(base_ast));
- Zir base_zir = loadStdImportZir(
- sema->module_root, sema->source_dir,
- base_import, &base_ast);
+ Zir base_zir = loadStdImportZir(sema->module_root,
+ sema->source_dir, base_import, &base_ast);
if (base_zir.inst_len > 0) {
const char* sub_import
= findDeclImportPathInZir(
&base_zir, mid_field);
if (sub_import) {
char base_dir[1024];
- computeSourceDir(
- sema->module_root,
- sema->source_dir,
- base_import, base_dir,
- sizeof(base_dir));
+ computeSourceDir(sema->module_root,
+ sema->source_dir, base_import,
+ base_dir, sizeof(base_dir));
import_zir = loadImportZir(
- base_dir, sub_import,
- &import_ast);
+ base_dir, sub_import, &import_ast);
zirDeinit(&base_zir);
astDeinit(&base_ast);
if (import_zir.inst_len > 0) {
- const char* fn_name
- = callee_name_idx
- ? (const char*)
- &sema->code
- .string_bytes
+ const char* fn_name = callee_name_idx
+ ? (const char*)&sema->code
+ .string_bytes
[callee_name_idx]
: fn_field;
- func_inst
- = findFuncInModuleZir(
- base_dir,
- &import_zir,
- &import_ast,
- fn_name);
- if (func_inst
- != UINT32_MAX) {
+ func_inst = findFuncInModuleZir(
+ base_dir, &import_zir, &import_ast,
+ fn_name);
+ if (func_inst != UINT32_MAX) {
saved_code = sema->code;
sema->code = import_zir;
is_cross_module = true;
@@ -2337,12 +2251,11 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
const char* field_name = NULL;
if (findDeclImportFieldVal(
sema, callee_name_idx, &import_path, &field_name)) {
- import_zir = loadImportZir(
- sema->source_dir, import_path, &import_ast);
+ import_zir
+ = loadImportZir(sema->source_dir, import_path, &import_ast);
if (import_zir.inst_len > 0) {
func_inst = findFuncInModuleZir(
- sema->source_dir,
- &import_zir, &import_ast, field_name);
+ sema->source_dir, &import_zir, &import_ast, field_name);
if (func_inst != UINT32_MAX) {
saved_code = sema->code;
sema->code = import_zir;
@@ -2376,11 +2289,10 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
uint32_t ret_ref = sema->code.extra[func_info.ret_ty_ref_pos];
if (ret_ref == IP_INDEX_TYPE_TYPE) {
const char* check_fn = callee_name_idx
- ? (is_cross_module
- ? (const char*)
- &saved_code.string_bytes[callee_name_idx]
- : (const char*)
- &sema->code.string_bytes[callee_name_idx])
+ ? (is_cross_module ? (const char*)&saved_code
+ .string_bytes[callee_name_idx]
+ : (const char*)&sema->code
+ .string_bytes[callee_name_idx])
: NULL;
if (check_fn && strcmp(check_fn, "Int") == 0) {
returns_type = true;
@@ -2395,6 +2307,36 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
}
}
+ // Determine which parameters are comptime (from callee's ZIR).
+ // Ported from src/Sema.zig lines 7104-7123: generate args to comptime
+ // params in comptime block.
+ bool is_ct_param[16];
+ memset(is_ct_param, 0, sizeof(is_ct_param));
+ bool is_generic = false;
+ {
+ uint32_t early_pb_inst
+ = sema->code
+ .extra[sema->code.inst_datas[func_inst].pl_node.payload_index
+ + func_info.param_block_pi];
+ const uint32_t* early_pb;
+ uint32_t early_pb_len;
+ getParamBody(sema, early_pb_inst, &early_pb, &early_pb_len);
+ uint32_t pi = 0;
+ for (uint32_t p = 0; p < early_pb_len; p++) {
+ ZirInstTag ptag = sema->code.inst_tags[early_pb[p]];
+ if (ptag == ZIR_INST_PARAM || ptag == ZIR_INST_PARAM_COMPTIME
+ || ptag == ZIR_INST_PARAM_ANYTYPE
+ || ptag == ZIR_INST_PARAM_ANYTYPE_COMPTIME) {
+ if (ptag == ZIR_INST_PARAM_COMPTIME
+ || ptag == ZIR_INST_PARAM_ANYTYPE_COMPTIME) {
+ is_ct_param[pi] = true;
+ is_generic = true;
+ }
+ pi++;
+ }
+ }
+ }
+
// Resolve the argument values (from the ORIGINAL module's ZIR).
// Each arg has a body that produces the argument value via
// break_inline.
@@ -2413,21 +2355,25 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
sema->code = saved_code;
uint32_t prev_end = args_len; // arg 0 starts after end-offset table
for (uint32_t a = 0; a < args_len; a++) {
- uint32_t arg_end_off
- = sema->code.extra[arg_data_start + a];
+ uint32_t arg_end_off = sema->code.extra[arg_data_start + a];
uint32_t arg_body_start = arg_data_start + prev_end;
uint32_t arg_body_len = arg_end_off - prev_end;
// Each arg body should end with a break_inline whose
// operand is the argument ref.
assert(arg_body_len >= 1);
+ // Ported from src/Sema.zig lines 7104-7123:
+ // Generate args to comptime params in comptime block.
+ bool saved_is_comptime = block->is_comptime;
+ if (is_ct_param[a])
+ block->is_comptime = true;
// Analyze preceding instructions in the arg body so that
// the break_inline operand is mapped. For simple args
// (e.g. param refs) arg_body_len==1 and this is a no-op.
if (arg_body_len > 1) {
(void)analyzeBodyInner(sema, block,
- &sema->code.extra[arg_body_start],
- arg_body_len - 1);
+ &sema->code.extra[arg_body_start], arg_body_len - 1);
}
+ block->is_comptime = saved_is_comptime;
uint32_t last_inst_idx
= sema->code.extra[arg_body_start + arg_body_len - 1];
ZirInstTag last_tag = sema->code.inst_tags[last_inst_idx];
@@ -2443,7 +2389,15 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
// Handle type-returning functions (e.g. std.meta.Int) whose result
// can be computed from the comptime arguments without inlining.
+ // Upstream always reserves a dead BLOCK before inlining; we match
+ // that here so the AIR tag array stays consistent.
if (returns_type) {
+ // returns_type functions return `type` which is comptime-only.
+ // Upstream evaluates these in comptime context, so
+ // need_debug_scope is always false → BLOCK tag.
+ AirInstData rt_dead;
+ memset(&rt_dead, 0, sizeof(rt_dead));
+ addAirInst(sema, AIR_INST_BLOCK, rt_dead);
uint8_t signedness = 0; // 0 = unsigned, 1 = signed
uint16_t bits_val = 0;
@@ -2457,22 +2411,17 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
// Extract signedness from arg 0's ZIR body (enum literal).
if (args_len >= 1) {
- Zir caller_zir
- = is_cross_module ? saved_code : sema->code;
- uint32_t arg0_end
- = caller_zir.extra[arg_data_start + 0];
+ Zir caller_zir = is_cross_module ? saved_code : sema->code;
+ uint32_t arg0_end = caller_zir.extra[arg_data_start + 0];
uint32_t arg0_body_start = arg_data_start + args_len;
uint32_t arg0_body_end = arg_data_start + arg0_end;
- for (uint32_t ai = arg0_body_start;
- ai < arg0_body_end; ai++) {
+ for (uint32_t ai = arg0_body_start; ai < arg0_body_end; ai++) {
uint32_t zi = caller_zir.extra[ai];
if (zi < caller_zir.inst_len
- && caller_zir.inst_tags[zi]
- == ZIR_INST_ENUM_LITERAL) {
- uint32_t str_idx
- = caller_zir.inst_datas[zi].str_tok.start;
- const char* lit = (const char*)
- &caller_zir.string_bytes[str_idx];
+ && caller_zir.inst_tags[zi] == ZIR_INST_ENUM_LITERAL) {
+ uint32_t str_idx = caller_zir.inst_datas[zi].str_tok.start;
+ const char* lit
+ = (const char*)&caller_zir.string_bytes[str_idx];
if (strcmp(lit, "signed") == 0)
signedness = 1;
break;
@@ -2506,9 +2455,10 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
}
// Parse the inline function's parameter body.
- uint32_t param_block_inst = sema->code.extra
- [sema->code.inst_datas[func_inst].pl_node.payload_index
- + func_info.param_block_pi];
+ uint32_t param_block_inst
+ = sema->code
+ .extra[sema->code.inst_datas[func_inst].pl_node.payload_index
+ + func_info.param_block_pi];
const uint32_t* param_body;
uint32_t param_body_len;
getParamBody(sema, param_block_inst, ¶m_body, ¶m_body_len);
@@ -2517,8 +2467,8 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
// For cross-module calls with anytype params (e.g. fneg), the return
// type is typically @TypeOf(a) which equals the first arg's type.
TypeIndex ret_ty = resolveFuncRetType(sema, &func_info);
- if (ret_ty == IP_INDEX_VOID_TYPE && is_cross_module
- && args_len > 0 && func_info.ret_ty_body_len > 1) {
+ if (ret_ty == IP_INDEX_VOID_TYPE && is_cross_module && args_len > 0
+ && func_info.ret_ty_body_len > 1) {
// Assume return type = first argument's type (covers @TypeOf(a)).
ret_ty = semaTypeOf(sema, arg_refs[0]);
}
@@ -2527,17 +2477,14 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
// map it to the corresponding argument value.
if (ret_ty == IP_INDEX_VOID_TYPE && args_len > 0
&& func_info.ret_ty_body_len == 1) {
- ZirInstRef ret_ty_ref
- = sema->code.extra[func_info.ret_ty_ref_pos];
+ ZirInstRef ret_ty_ref = sema->code.extra[func_info.ret_ty_ref_pos];
if (ret_ty_ref >= ZIR_REF_START_INDEX) {
uint32_t ret_ty_inst = ret_ty_ref - ZIR_REF_START_INDEX;
// Match the return type inst against param body insts.
uint32_t pi = 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
+ 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) {
if (param_body[p] == ret_ty_inst && pi < args_len) {
@@ -2556,14 +2503,29 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
// Non-inline functions: emit CALL instruction instead of inlining.
// Ported from Sema.zig analyzeCall (non-inline path, lines 7575-7601).
if (!func_info.is_inline) {
+ // For generic functions, emit dummy ALLOC for non-comptime
+ // runtime parameters. Upstream does this at Sema.zig:7397
+ // to give generic_inst_map a typed placeholder for the
+ // generic return-type body. The instruction is appended
+ // directly to the AIR (not to any block).
+ if (is_generic && !block->is_comptime) {
+ for (uint32_t a = 0; a < args_len; a++) {
+ if (!is_ct_param[a]) {
+ TypeIndex arg_ty = semaTypeOf(sema, arg_refs[a]);
+ AirInstData dummy;
+ memset(&dummy, 0, sizeof(dummy));
+ dummy.ty.ty_ref = AIR_REF_FROM_IP(arg_ty);
+ addAirInst(sema, AIR_INST_ALLOC, dummy);
+ }
+ }
+ }
// Count runtime params (skip comptime type params).
uint32_t runtime_args_count = 0;
AirInstRef runtime_arg_refs[16];
uint32_t pi = 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_ANYTYPE) {
+ if (ptag == ZIR_INST_PARAM || ptag == ZIR_INST_PARAM_ANYTYPE) {
if (pi < args_len)
runtime_arg_refs[runtime_args_count++] = arg_refs[pi];
pi++;
@@ -2588,19 +2550,6 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
fv_key.data.func = func_type_ip + func_inst;
InternPoolIndex func_val_ip = ipIntern(sema->ip, fv_key);
- // Emit result location ALLOC for the CALL return value.
- // Ported from upstream Sema.zig analyzeCall (result location).
- InternPoolKey alloc_key;
- memset(&alloc_key, 0, sizeof(alloc_key));
- alloc_key.tag = IP_KEY_PTR_TYPE;
- alloc_key.data.ptr_type.child = ret_ty;
- alloc_key.data.ptr_type.flags = 0;
- TypeIndex alloc_ptr_ty = ipIntern(sema->ip, alloc_key);
- AirInstData alloc_data;
- memset(&alloc_data, 0, sizeof(alloc_data));
- alloc_data.ty.ty_ref = AIR_REF_FROM_IP(alloc_ptr_ty);
- blockAddInst(block, AIR_INST_ALLOC, alloc_data);
-
// Emit CALL extra: {args_len, arg_refs[0..args_len]}.
uint32_t call_extra = addAirExtra(sema, runtime_args_count);
for (uint32_t a = 0; a < runtime_args_count; a++)
@@ -2611,13 +2560,11 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
memset(&call_data, 0, sizeof(call_data));
call_data.pl_op.operand = AIR_REF_FROM_IP(func_val_ip);
call_data.pl_op.payload = call_extra;
- AirInstRef call_ref = blockAddInst(
- block, AIR_INST_CALL, call_data);
+ AirInstRef call_ref = blockAddInst(block, AIR_INST_CALL, call_data);
// Register CALL return type for semaTypeOf.
if (sema->num_calls < 16) {
- sema->call_air_insts[sema->num_calls]
- = AIR_REF_TO_INST(call_ref);
+ sema->call_air_insts[sema->num_calls] = AIR_REF_TO_INST(call_ref);
sema->call_ret_types[sema->num_calls] = ret_ty;
sema->num_calls++;
}
@@ -2632,37 +2579,37 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
}
// Memoization: check if we've seen this function with the same
- // comptime args before. We memoize aggressively (even in
- // non-comptime blocks) because we can't fully resolve all comptime
- // declarations. This compensates for missing features.
- // TODO: switch to upstream matching (block->is_comptime && args_len>0)
- // once namespace function calls are properly resolved.
- bool all_comptime = (args_len > 0);
- for (uint32_t a = 0; a < args_len && all_comptime; a++) {
- if (!AIR_REF_IS_IP(arg_refs[a]))
- all_comptime = false;
+ // comptime args before.
+ // Ported from src/Sema.zig line 7712: want_memoize = block.isComptime().
+ bool all_comptime = block->is_comptime && args_len > 0;
+ if (all_comptime) {
+ for (uint32_t a = 0; a < args_len; a++) {
+ if (!AIR_REF_IS_IP(arg_refs[a])) {
+ all_comptime = false;
+ break;
+ }
+ }
}
if (all_comptime) {
- for (uint32_t ci = 0; ci < sema->num_memo; ci++) {
- if (sema->memo_func_inst[ci] != func_inst)
+ for (uint32_t mi = 0; mi < sema->num_memo; mi++) {
+ if (sema->memo_func_inst[mi] != func_inst)
continue;
- if (sema->memo_args_len[ci] != args_len)
+ if (sema->memo_args_len[mi] != args_len)
continue;
bool match = true;
- for (uint32_t a = 0; a < args_len; a++) {
- if (sema->memo_args[ci][a] != arg_refs[a]) {
+ for (uint32_t a = 0; a < args_len && a < 4; a++) {
+ if (sema->memo_args[mi][a] != arg_refs[a]) {
match = false;
break;
}
}
if (match) {
- // Cached result found — skip inline expansion.
if (is_cross_module) {
sema->code = saved_code;
zirDeinit(&import_zir);
astDeinit(&import_ast);
}
- return sema->memo_result[ci];
+ return sema->memo_result[mi];
}
}
}
@@ -2671,15 +2618,12 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
// When comptime (or all args comptime), use BLOCK; otherwise
// DBG_INLINE_BLOCK.
bool need_debug_scope = !block->is_comptime;
- AirInstTag block_tag = need_debug_scope
- ? AIR_INST_DBG_INLINE_BLOCK
- : AIR_INST_BLOCK;
+ AirInstTag block_tag
+ = need_debug_scope ? AIR_INST_DBG_INLINE_BLOCK : AIR_INST_BLOCK;
// Reserve the block instruction (data filled later).
- uint32_t block_inst_idx = addAirInst(sema,
- block_tag,
- (AirInstData){ .ty_pl = { .ty_ref = 0, .payload = 0 } });
-
+ uint32_t block_inst_idx = addAirInst(sema, block_tag,
+ (AirInstData) { .ty_pl = { .ty_ref = 0, .payload = 0 } });
// Set up child block for inlining.
SemaBlockMerges merges;
@@ -2712,8 +2656,7 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
child_block.need_debug_scope = NULL;
// Map param ZIR instructions to the argument values.
- instMapEnsureSpaceForBody(
- &sema->inst_map, param_body, param_body_len);
+ instMapEnsureSpaceForBody(&sema->inst_map, param_body, param_body_len);
uint32_t param_idx = 0;
for (uint32_t p = 0; p < param_body_len; p++) {
ZirInstTag ptag = sema->code.inst_tags[param_body[p]];
@@ -2724,35 +2667,28 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
sema->has_compile_errors = true;
return AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
}
- instMapPut(
- &sema->inst_map, param_body[p], arg_refs[param_idx]);
+ instMapPut(&sema->inst_map, param_body[p], arg_refs[param_idx]);
// Emit dbg_arg_inline for runtime params only.
// Comptime params (param_comptime, param_anytype_comptime)
// are skipped because their types are comptime-only.
- if (!child_block.is_comptime
- && ptag != ZIR_INST_PARAM_COMPTIME
+ if (!child_block.is_comptime && ptag != ZIR_INST_PARAM_COMPTIME
&& ptag != ZIR_INST_PARAM_ANYTYPE_COMPTIME) {
uint32_t param_name_idx;
- if (ptag == ZIR_INST_PARAM_ANYTYPE
- || ptag == ZIR_INST_PARAM_ANYTYPE_COMPTIME) {
+ if (ptag == ZIR_INST_PARAM_ANYTYPE) {
// str_tok: name is at str_tok.start.
param_name_idx
- = sema->code.inst_datas[param_body[p]]
- .str_tok.start;
+ = sema->code.inst_datas[param_body[p]].str_tok.start;
} else {
// pl_tok: name is extra[payload_index + 0].
uint32_t param_payload
= sema->code.inst_datas[param_body[p]]
.pl_tok.payload_index;
- param_name_idx
- = sema->code.extra[param_payload];
+ param_name_idx = sema->code.extra[param_payload];
}
const char* param_name
- = (const char*)&sema->code
- .string_bytes[param_name_idx];
- uint32_t name_nts
- = semaAppendAirString(sema, param_name);
+ = (const char*)&sema->code.string_bytes[param_name_idx];
+ uint32_t name_nts = semaAppendAirString(sema, param_name);
AirInstData data;
memset(&data, 0, sizeof(data));
data.pl_op.operand = arg_refs[param_idx];
@@ -2784,11 +2720,9 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
}
// Analyze the inline function body.
- const uint32_t* func_body
- = &sema->code.extra[func_info.extra_index];
+ const uint32_t* func_body = &sema->code.extra[func_info.extra_index];
- (void)analyzeBodyInner(
- sema, &child_block, func_body, func_info.body_len);
+ (void)analyzeBodyInner(sema, &child_block, func_body, func_info.body_len);
// Restore decl table for cross-module calls.
if (is_cross_module) {
@@ -2801,6 +2735,36 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
sema->fn_ret_ty = saved_fn_ret_ty;
+ // ComptimeReturn: the inline function returned at comptime.
+ // Skip block finalization — no AIR instructions emitted.
+ // Roll back AIR state to discard the reserved block and any body
+ // instructions (they are dead). Ported from src/Sema.zig line 7872.
+ if (inlining.comptime_returned) {
+ AirInstRef ct_result = inlining.comptime_result;
+
+ // Cache comptime results for memoization.
+ if (all_comptime && AIR_REF_IS_IP(ct_result)) {
+ if (sema->num_memo < 32) {
+ uint32_t mi = sema->num_memo++;
+ sema->memo_func_inst[mi] = func_inst;
+ sema->memo_args_len[mi] = args_len;
+ for (uint32_t a = 0; a < args_len && a < 4; a++)
+ sema->memo_args[mi][a] = arg_refs[a];
+ sema->memo_result[mi] = ct_result;
+ }
+ }
+
+ free(inlining.merges.results);
+ free(inlining.merges.br_list);
+ semaBlockDeinit(&child_block);
+ if (is_cross_module) {
+ sema->code = saved_code;
+ zirDeinit(&import_zir);
+ astDeinit(&import_ast);
+ }
+ return ct_result;
+ }
+
// Resolve the inline call block, ported from resolveAnalyzedBlock.
AirInstRef result_ref = AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
if (inlining.merges.results_len > 0)
@@ -2828,16 +2792,15 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
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
+ = realloc(block->instructions, nc * sizeof(uint32_t));
block->instructions_cap = nc;
}
block->instructions[block->instructions_len++]
= child_block.instructions[i];
}
call_result = AIR_REF_FROM_INST(
- child_block
- .instructions[child_block.instructions_len - 1]);
+ child_block.instructions[child_block.instructions_len - 1]);
} else {
// dbg_inline_block: create block with noreturn type.
uint32_t es = addAirExtra(sema, inlining.func);
@@ -2849,38 +2812,34 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
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
+ = realloc(block->instructions, nc * sizeof(uint32_t));
block->instructions_cap = nc;
}
- block->instructions[block->instructions_len++]
- = block_inst_idx;
+ block->instructions[block->instructions_len++] = block_inst_idx;
call_result = AIR_REF_FROM_INST(block_inst_idx);
}
} else if (inlining.merges.results_len == 1) {
// Single result. Try to elide block when !need_debug_scope.
bool elided = false;
if (!need_debug_scope && child_block.instructions_len > 0) {
- uint32_t last = child_block.instructions[
- child_block.instructions_len - 1];
+ uint32_t last
+ = child_block.instructions[child_block.instructions_len - 1];
if (sema->air_inst_tags[last] == AIR_INST_BR
&& sema->air_inst_datas[last].br.block_inst
== block_inst_idx) {
// Elide: copy instructions except trailing break.
- for (uint32_t i = 0;
- i < child_block.instructions_len - 1; i++) {
- if (block->instructions_len
- >= block->instructions_cap) {
+ for (uint32_t i = 0; i < child_block.instructions_len - 1;
+ 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, nc * sizeof(uint32_t));
block->instructions_cap = nc;
}
block->instructions[block->instructions_len++]
= child_block.instructions[i];
}
- call_result = result_ref;
elided = true;
}
}
@@ -2908,12 +2867,11 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
}
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
+ = realloc(block->instructions, nc * sizeof(uint32_t));
block->instructions_cap = nc;
}
- block->instructions[block->instructions_len++]
- = block_inst_idx;
+ block->instructions[block->instructions_len++] = block_inst_idx;
call_result = result_ref;
} else if (!elided) {
// Runtime result: create block with result type.
@@ -2932,12 +2890,11 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
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
+ = realloc(block->instructions, nc * sizeof(uint32_t));
block->instructions_cap = nc;
}
- block->instructions[block->instructions_len++]
- = block_inst_idx;
+ block->instructions[block->instructions_len++] = block_inst_idx;
call_result = AIR_REF_FROM_INST(block_inst_idx);
} else {
call_result = result_ref;
@@ -2959,8 +2916,8 @@ static AirInstRef zirCall(Sema* sema, SemaBlock* block, uint32_t inst,
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
+ = realloc(block->instructions, nc * sizeof(uint32_t));
block->instructions_cap = nc;
}
block->instructions[block->instructions_len++] = block_inst_idx;
@@ -3108,14 +3065,14 @@ static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) {
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 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];
ZirInstTag first_tag = sema->code.inst_tags[first_inst];
if (first_tag == ZIR_INST_PTR_TYPE) {
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;
+ 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];
@@ -3210,12 +3167,14 @@ static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) {
= 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]; // PtrType.elem_type
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)) // ZIR bit 1 = is_mutable; !is_mutable → const
ip_flags |= PTR_FLAGS_IS_CONST;
InternPoolKey key;
memset(&key, 0, sizeof(key));
@@ -3430,10 +3389,8 @@ static void zirStructDecl(Sema* sema, SemaBlock* block, uint32_t inst) {
const uint32_t* value_body = &sema->code.extra[di];
bool is_func = false;
for (uint32_t vi = 0; vi < value_body_len; vi++) {
- ZirInstTag vtag
- = sema->code.inst_tags[value_body[vi]];
- if (vtag == ZIR_INST_FUNC
- || vtag == ZIR_INST_FUNC_FANCY) {
+ ZirInstTag vtag = sema->code.inst_tags[value_body[vi]];
+ if (vtag == ZIR_INST_FUNC || vtag == ZIR_INST_FUNC_FANCY) {
is_func = true;
break;
}
@@ -3461,8 +3418,7 @@ static void zirStructDecl(Sema* sema, SemaBlock* block, uint32_t inst) {
// zirTypeof: handle @TypeOf(operand).
// Returns the type of the operand as an IP ref.
static AirInstRef zirTypeof(Sema* sema, uint32_t inst) {
- ZirInstRef operand_ref
- = sema->code.inst_datas[inst].un_node.operand;
+ ZirInstRef operand_ref = sema->code.inst_datas[inst].un_node.operand;
AirInstRef operand = resolveInst(sema, operand_ref);
TypeIndex ty = semaTypeOf(sema, operand);
return AIR_REF_FROM_IP(ty);
@@ -3475,8 +3431,7 @@ static AirInstRef zirTypeof(Sema* sema, uint32_t inst) {
// Returns the result value from the matched break instruction.
static AirInstRef zirSwitchBlockComptime(
Sema* sema, SemaBlock* block, uint32_t inst) {
- uint32_t payload_index
- = sema->code.inst_datas[inst].pl_node.payload_index;
+ uint32_t payload_index = sema->code.inst_datas[inst].pl_node.payload_index;
ZirInstRef operand_ref = sema->code.extra[payload_index];
uint32_t bits = sema->code.extra[payload_index + 1];
@@ -3561,8 +3516,7 @@ static AirInstRef zirSwitchBlockComptime(
&& AIR_REF_TO_IP(operand) == AIR_REF_TO_IP(item))
match = true;
else if (isComptimeInt(sema, operand, &op_val)
- && isComptimeInt(sema, item, &item_val)
- && op_val == item_val)
+ && isComptimeInt(sema, item, &item_val) && op_val == item_val)
match = true;
if (match) {
// Match found. Analyze the body via resolveBlockBody.
@@ -3579,8 +3533,7 @@ static AirInstRef zirSwitchBlockComptime(
// debug undefined pattern.
AirInstData block_data;
memset(&block_data, 0xaa, sizeof(block_data));
- uint32_t block_inst
- = addAirInst(sema, AIR_INST_BLOCK, block_data);
+ uint32_t block_inst = addAirInst(sema, AIR_INST_BLOCK, block_data);
// Set up a label so break can find this block.
SemaBlockLabel label;
@@ -3588,21 +3541,19 @@ static AirInstRef zirSwitchBlockComptime(
label.zir_block = inst;
label.merges.block_inst = block_inst;
- // Non-comptime child block (matches Zig line 11942-11959).
- // The break handler will add a BR instruction.
+ // Child block inherits comptime from parent (matches Zig
+ // line 11942-11959: comptime_reason is inherited).
+ // In comptime context, the break handler records the
+ // result without emitting a BR, matching upstream where
+ // only the dead BLOCK remains.
SemaBlock child_block;
semaBlockInit(&child_block, sema, block);
- child_block.is_comptime = false;
+ child_block.is_comptime = block->is_comptime;
child_block.inlining = block->inlining;
child_block.label = &label;
- (void)analyzeBodyInner(
- sema, &child_block, body, body_len);
+ (void)analyzeBodyInner(sema, &child_block, body, body_len);
- // resolveAnalyzedBlock elides the block: the single break
- // is the last instruction in child_block, targeting our
- // block_inst, so instructions are not added to parent.
- // Both BLOCK and BR remain as dead AIR instructions.
AirInstRef result;
if (label.merges.results_len > 0)
result = label.merges.results[0];
@@ -3636,8 +3587,7 @@ static AirInstRef zirSwitchBlockComptime(
// Reserve BLOCK instruction (same as scalar case above).
AirInstData block_data;
memset(&block_data, 0xaa, sizeof(block_data));
- uint32_t block_inst
- = addAirInst(sema, AIR_INST_BLOCK, block_data);
+ uint32_t block_inst = addAirInst(sema, AIR_INST_BLOCK, block_data);
SemaBlockLabel label;
memset(&label, 0, sizeof(label));
@@ -3646,12 +3596,11 @@ static AirInstRef zirSwitchBlockComptime(
SemaBlock child_block;
semaBlockInit(&child_block, sema, block);
- child_block.is_comptime = false;
+ child_block.is_comptime = block->is_comptime;
child_block.inlining = block->inlining;
child_block.label = &label;
- (void)analyzeBodyInner(
- sema, &child_block, body, else_body_len);
+ (void)analyzeBodyInner(sema, &child_block, body, else_body_len);
AirInstRef result;
if (label.merges.results_len > 0)
@@ -3671,8 +3620,7 @@ static AirInstRef zirSwitchBlockComptime(
// zirTypeInfoComptime: handle @typeInfo(type_ref) at comptime.
// For float types, tracks the result for subsequent field_val access.
static AirInstRef zirTypeInfoComptime(Sema* sema, uint32_t inst) {
- ZirInstRef operand_ref
- = sema->code.inst_datas[inst].un_node.operand;
+ ZirInstRef operand_ref = sema->code.inst_datas[inst].un_node.operand;
AirInstRef operand = resolveInst(sema, operand_ref);
// operand should be an IP ref to a type.
if (!AIR_REF_IS_IP(operand))
@@ -3698,12 +3646,18 @@ static AirInstRef zirTypeInfoComptime(Sema* sema, uint32_t inst) {
// floatTypeBits: get the bit count for a float type IP index.
static uint32_t floatTypeBits(InternPoolIndex ty) {
switch (ty) {
- case IP_INDEX_F16_TYPE: return 16;
- case IP_INDEX_F32_TYPE: return 32;
- case IP_INDEX_F64_TYPE: return 64;
- case IP_INDEX_F80_TYPE: return 80;
- case IP_INDEX_F128_TYPE: return 128;
- default: return 0;
+ case IP_INDEX_F16_TYPE:
+ return 16;
+ case IP_INDEX_F32_TYPE:
+ return 32;
+ case IP_INDEX_F64_TYPE:
+ return 64;
+ case IP_INDEX_F80_TYPE:
+ return 80;
+ case IP_INDEX_F128_TYPE:
+ return 128;
+ default:
+ return 0;
}
}
@@ -3744,8 +3698,7 @@ static AirInstRef zirBitSizeOf(Sema* sema, uint32_t inst) {
// zirFieldValComptime: handle field_val on comptime values.
// Resolves .float on type_info results and .bits on float_info.
static AirInstRef zirFieldValComptime(Sema* sema, uint32_t inst) {
- uint32_t payload_index
- = sema->code.inst_datas[inst].pl_node.payload_index;
+ uint32_t payload_index = sema->code.inst_datas[inst].pl_node.payload_index;
ZirInstRef obj_ref = sema->code.extra[payload_index];
uint32_t field_name_start = sema->code.extra[payload_index + 1];
const char* field_name
@@ -3794,13 +3747,16 @@ static AirInstRef zirFieldValComptime(Sema* sema, uint32_t inst) {
// resolveUnsignedIntType: given a bits count, return the IP index
// for the corresponding unsigned integer type.
-static InternPoolIndex resolveUnsignedIntType(
- InternPool* ip, uint32_t bits) {
+static InternPoolIndex resolveUnsignedIntType(InternPool* ip, uint32_t bits) {
switch (bits) {
- case 8: return IP_INDEX_U8_TYPE;
- case 16: return IP_INDEX_U16_TYPE;
- case 32: return IP_INDEX_U32_TYPE;
- case 64: return IP_INDEX_U64_TYPE;
+ case 8:
+ return IP_INDEX_U8_TYPE;
+ case 16:
+ return IP_INDEX_U16_TYPE;
+ case 32:
+ return IP_INDEX_U32_TYPE;
+ case 64:
+ return IP_INDEX_U64_TYPE;
default: {
// Intern a new int type.
InternPoolKey key;
@@ -3818,8 +3774,7 @@ static InternPoolIndex resolveUnsignedIntType(
// - inner struct: extract signedness and bits, track as CT_TAG_INT_INFO
// - outer struct: extract field name (.int), track as CT_TAG_REIFY_INT
static AirInstRef zirStructInitComptime(Sema* sema, uint32_t inst) {
- uint32_t payload_index
- = sema->code.inst_datas[inst].pl_node.payload_index;
+ uint32_t payload_index = sema->code.inst_datas[inst].pl_node.payload_index;
// StructInit payload: abs_node, abs_line, fields_len, then Items.
uint32_t fields_len = sema->code.extra[payload_index + 2];
const uint32_t* items = &sema->code.extra[payload_index + 3];
@@ -3841,8 +3796,7 @@ static AirInstRef zirStructInitComptime(Sema* sema, uint32_t inst) {
uint32_t ft_payload
= sema->code.inst_datas[field_type_inst].pl_node.payload_index;
uint32_t name_start = sema->code.extra[ft_payload + 1];
- const char* name
- = (const char*)&sema->code.string_bytes[name_start];
+ const char* name = (const char*)&sema->code.string_bytes[name_start];
AirInstRef init_air = resolveInst(sema, init_ref);
@@ -3883,16 +3837,14 @@ static AirInstRef zirStructInitComptime(Sema* sema, uint32_t inst) {
if (has_signedness && has_bits) {
// Inner struct: .{.signedness = S, .bits = N}
- key.data.int_val.value = 0x51F70000
- | ((uint64_t)signedness << 16) | bits_val;
+ key.data.int_val.value
+ = 0x51F70000 | ((uint64_t)signedness << 16) | bits_val;
InternPoolIndex marker = ipIntern(sema->ip, key);
- ctTrack(sema, marker, CT_TAG_INT_INFO,
- (signedness << 16) | bits_val);
+ ctTrack(sema, marker, CT_TAG_INT_INFO, (signedness << 16) | bits_val);
return AIR_REF_FROM_IP(marker);
}
- if (outer_field_name != NULL
- && strcmp(outer_field_name, "int") == 0) {
+ if (outer_field_name != NULL && strcmp(outer_field_name, "int") == 0) {
// Outer struct: .{.int = <inner>}
key.data.int_val.value = 0x52E10000 + inner_ip;
InternPoolIndex marker = ipIntern(sema->ip, key);
@@ -3929,8 +3881,7 @@ static AirInstRef zirReifyComptime(Sema* sema, uint32_t inst) {
uint32_t s = (inner_val >> 16) & 0xFFFF;
uint32_t b = inner_val & 0xFFFF;
if (s == 0) {
- return AIR_REF_FROM_IP(
- resolveUnsignedIntType(sema->ip, b));
+ return AIR_REF_FROM_IP(resolveUnsignedIntType(sema->ip, b));
}
// Signed int type.
InternPoolKey key;
@@ -3945,8 +3896,7 @@ static AirInstRef zirReifyComptime(Sema* sema, uint32_t inst) {
uint32_t s = (ct_val >> 16) & 0xFFFF;
uint32_t b = ct_val & 0xFFFF;
if (s == 0) {
- return AIR_REF_FROM_IP(
- resolveUnsignedIntType(sema->ip, b));
+ return AIR_REF_FROM_IP(resolveUnsignedIntType(sema->ip, b));
}
InternPoolKey key;
memset(&key, 0, sizeof(key));
@@ -3962,8 +3912,7 @@ static AirInstRef zirReifyComptime(Sema* sema, uint32_t inst) {
// zirDeclLiteralComptime: handle decl_literal in comptime context.
// For enum literals like .unsigned, resolve to the enum value.
static AirInstRef zirDeclLiteralComptime(Sema* sema, uint32_t inst) {
- uint32_t payload_index
- = sema->code.inst_datas[inst].pl_node.payload_index;
+ uint32_t payload_index = sema->code.inst_datas[inst].pl_node.payload_index;
// Field payload: lhs(Ref), field_name_start(u32).
uint32_t field_name_start = sema->code.extra[payload_index + 1];
const char* field_name
@@ -3993,15 +3942,14 @@ static AirInstRef zirDeclLiteralComptime(Sema* sema, uint32_t inst) {
// --- mergesAppend ---
// Append a result and br instruction index to a SemaBlockMerges.
-static void mergesAppend(SemaBlockMerges* merges,
- AirInstRef result, uint32_t br_inst) {
+static void mergesAppend(
+ SemaBlockMerges* merges, AirInstRef result, uint32_t br_inst) {
if (merges->results_len >= merges->results_cap) {
uint32_t new_cap
= (merges->results_cap == 0) ? 4 : merges->results_cap * 2;
merges->results
= realloc(merges->results, new_cap * sizeof(AirInstRef));
- merges->br_list
- = realloc(merges->br_list, new_cap * sizeof(uint32_t));
+ merges->br_list = realloc(merges->br_list, new_cap * sizeof(uint32_t));
if (!merges->results || !merges->br_list)
exit(1);
merges->results_cap = new_cap;
@@ -4081,27 +4029,30 @@ static bool analyzeBodyInner(
operand = semaCoerce(sema, block, sema->fn_ret_ty, operand);
if (block->inlining) {
- // Inlining: rewrite ret as br to the inline block.
// Ported from src/Sema.zig analyzeRet (inlining path).
SemaBlockInlining* inl = block->inlining;
+ // Comptime inlining: signal ComptimeReturn instead of
+ // emitting a BR. Ported from Sema.zig lines 18955-18964.
+ if (block->is_comptime) {
+ inl->comptime_result = operand;
+ inl->comptime_returned = true;
+ return false;
+ }
+ // Runtime inlining: rewrite ret as br to the inline block.
AirInstData br_data;
memset(&br_data, 0, sizeof(br_data));
br_data.br.block_inst = inl->merges.block_inst;
br_data.br.operand = operand;
- AirInstRef br_ref
- = blockAddInst(block, AIR_INST_BR, br_data);
+ AirInstRef br_ref = blockAddInst(block, AIR_INST_BR, br_data);
// Record merge result and br instruction.
if (inl->merges.results_len >= inl->merges.results_cap) {
- uint32_t new_cap
- = (inl->merges.results_cap == 0)
+ uint32_t new_cap = (inl->merges.results_cap == 0)
? 4
: inl->merges.results_cap * 2;
inl->merges.results = realloc(
- inl->merges.results,
- new_cap * sizeof(AirInstRef));
+ inl->merges.results, new_cap * sizeof(AirInstRef));
inl->merges.br_list = realloc(
- inl->merges.br_list,
- new_cap * sizeof(uint32_t));
+ inl->merges.br_list, new_cap * sizeof(uint32_t));
if (!inl->merges.results || !inl->merges.br_list)
exit(1);
inl->merges.results_cap = new_cap;
@@ -4167,21 +4118,21 @@ static bool analyzeBodyInner(
// when the callee is a decl_val/decl_ref.
case ZIR_INST_DECL_VAL:
case ZIR_INST_DECL_REF:
- instMapPut(&sema->inst_map, inst,
- AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE));
+ instMapPut(
+ &sema->inst_map, inst, AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE));
i++;
continue;
// call / field_call: function call.
// Handles inline function calls from the same module.
case ZIR_INST_CALL:
- instMapPut(&sema->inst_map, inst,
- zirCall(sema, block, inst, false));
+ instMapPut(
+ &sema->inst_map, inst, zirCall(sema, block, inst, false));
i++;
continue;
case ZIR_INST_FIELD_CALL:
- instMapPut(&sema->inst_map, inst,
- zirCall(sema, block, inst, true));
+ instMapPut(
+ &sema->inst_map, inst, zirCall(sema, block, inst, true));
i++;
continue;
@@ -4205,16 +4156,13 @@ static bool analyzeBodyInner(
// Extra: {src_node, operand (ZIR ref)}.
uint32_t payload_index
= sema->code.inst_datas[inst].extended.operand;
- ZirInstRef hint_ref
- = sema->code.extra[payload_index + 1];
+ ZirInstRef hint_ref = sema->code.extra[payload_index + 1];
AirInstRef resolved = resolveInst(sema, hint_ref);
- if (AIR_REF_IS_IP(resolved)
- && sema->branch_hint < 0) {
- InternPoolKey key = ipIndexToKey(
- sema->ip, AIR_REF_TO_IP(resolved));
+ if (AIR_REF_IS_IP(resolved) && sema->branch_hint < 0) {
+ InternPoolKey key
+ = ipIndexToKey(sema->ip, AIR_REF_TO_IP(resolved));
if (key.tag == IP_KEY_INT) {
- sema->branch_hint
- = (int8_t)key.data.int_val.value;
+ sema->branch_hint = (int8_t)key.data.int_val.value;
}
}
air_ref = AIR_REF_FROM_IP(IP_INDEX_VOID_TYPE);
@@ -4222,7 +4170,8 @@ static bool analyzeBodyInner(
// Ported from src/Sema.zig zirInplaceArithResultTy.
// operand is the ZIR ref of the loaded LHS value.
// For non-pointer types, the result type is the LHS type.
- uint32_t operand = sema->code.inst_datas[inst].extended.operand;
+ uint32_t operand
+ = sema->code.inst_datas[inst].extended.operand;
AirInstRef lhs = resolveInst(sema, operand);
TypeIndex lhs_ty = semaTypeOf(sema, lhs);
air_ref = AIR_REF_FROM_IP(lhs_ty);
@@ -4247,9 +4196,9 @@ static bool analyzeBodyInner(
// this block_inline, requiring a post-hoc BLOCK wrapper
// for correct lexical scoping.
// Ported from src/Sema.zig block_inline need_debug_scope.
- bool need_debug_scope = false;
+ volatile bool need_debug_scope = false;
bool* saved_need_debug_scope = block->need_debug_scope;
- block->need_debug_scope = &need_debug_scope;
+ block->need_debug_scope = (bool*)&need_debug_scope;
uint32_t block_index = block->instructions_len;
bool completed
@@ -4267,53 +4216,42 @@ static bool analyzeBodyInner(
= block->instructions_len - block_index;
// Reserve an AIR block instruction.
- uint32_t blk_inst = addAirInst(sema,
- AIR_INST_BLOCK,
- (AirInstData){
- .ty_pl = { .ty_ref = 0, .payload = 0 }
- });
+ uint32_t blk_inst = addAirInst(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 = addAirInst(
- sema, AIR_INST_BR, br_data);
+ br_data.br.operand = AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
+ uint32_t br_inst = addAirInst(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
- = addAirExtra(sema, body_len2);
- for (uint32_t ci = block_index;
- ci < block->instructions_len; ci++) {
- addAirExtra(sema,
- block->instructions[ci]);
+ uint32_t extra_start = addAirExtra(sema, body_len2);
+ for (uint32_t ci = block_index; ci < block->instructions_len;
+ ci++) {
+ addAirExtra(sema, block->instructions[ci]);
}
addAirExtra(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;
+ 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;
+ 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, new_cap * sizeof(uint32_t));
+ if (!block->instructions)
+ exit(1);
block->instructions_cap = new_cap;
}
- block->instructions[block->instructions_len++]
- = blk_inst;
+ block->instructions[block->instructions_len++] = blk_inst;
}
if (!completed) {
@@ -4323,8 +4261,7 @@ static bool analyzeBodyInner(
uint32_t break_inst_zir = sema->comptime_break_inst;
ZirInstData break_data_zir
= sema->code.inst_datas[break_inst_zir];
- ZirInstRef operand
- = break_data_zir.break_data.operand;
+ ZirInstRef operand = break_data_zir.break_data.operand;
AirInstRef result;
if (operand == ZIR_REF_NONE) {
result = AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
@@ -4353,24 +4290,20 @@ static bool analyzeBodyInner(
= sema->code.inst_datas[inst].pl_node.payload_index;
uint32_t exported_ref = sema->code.extra[payload_index];
if (exported_ref >= ZIR_REF_START_INDEX) {
- uint32_t exported_inst
- = exported_ref - ZIR_REF_START_INDEX;
+ uint32_t exported_inst = exported_ref - ZIR_REF_START_INDEX;
ZirInstTag etag = sema->code.inst_tags[exported_inst];
- if (etag == ZIR_INST_DECL_REF
- || etag == ZIR_INST_DECL_VAL) {
+ if (etag == ZIR_INST_DECL_REF || etag == ZIR_INST_DECL_VAL) {
uint32_t name_idx
- = sema->code.inst_datas[exported_inst]
- .str_tok.start;
+ = sema->code.inst_datas[exported_inst].str_tok.start;
if (sema->num_exported_decl_names
< MAX_EXPORTED_DECL_NAMES) {
- s_exported_decl_names
- [sema->num_exported_decl_names++] = name_idx;
+ s_exported_decl_names[sema->num_exported_decl_names++]
+ = name_idx;
}
}
}
instMapPut(
- &sema->inst_map, inst,
- AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE));
+ &sema->inst_map, inst, AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE));
i++;
continue;
}
@@ -4478,8 +4411,7 @@ static bool analyzeBodyInner(
// @bitCast.
case ZIR_INST_BITCAST:
- instMapPut(&sema->inst_map, inst,
- zirBitcast(sema, block, inst));
+ instMapPut(&sema->inst_map, inst, zirBitcast(sema, block, inst));
i++;
continue;
@@ -4513,8 +4445,7 @@ static bool analyzeBodyInner(
// @floatCast.
case ZIR_INST_FLOAT_CAST:
- instMapPut(&sema->inst_map, inst,
- zirFloatCast(sema, block, inst));
+ instMapPut(&sema->inst_map, inst, zirFloatCast(sema, block, inst));
i++;
continue;
@@ -4544,8 +4475,7 @@ static bool analyzeBodyInner(
// @as.
case ZIR_INST_AS_NODE:
- instMapPut(&sema->inst_map, inst,
- zirAsNode(sema, block, inst));
+ instMapPut(&sema->inst_map, inst, zirAsNode(sema, block, inst));
i++;
continue;
@@ -4557,35 +4487,31 @@ static bool analyzeBodyInner(
// Load (pointer dereference).
case ZIR_INST_LOAD:
- instMapPut(&sema->inst_map, inst,
- zirLoad(sema, block, inst));
+ instMapPut(&sema->inst_map, inst, zirLoad(sema, block, inst));
i++;
continue;
// Unary operations.
case ZIR_INST_NEGATE:
- instMapPut(&sema->inst_map, inst,
- zirNegate(sema, block, inst));
+ instMapPut(&sema->inst_map, inst, zirNegate(sema, block, inst));
i++;
continue;
case ZIR_INST_BIT_NOT:
- instMapPut(&sema->inst_map, inst,
- zirBitNot(sema, block, inst));
+ instMapPut(&sema->inst_map, inst, zirBitNot(sema, block, inst));
i++;
continue;
case ZIR_INST_BOOL_NOT:
- instMapPut(&sema->inst_map, inst,
- zirBoolNot(sema, block, inst));
+ instMapPut(&sema->inst_map, inst, zirBoolNot(sema, block, inst));
i++;
continue;
case ZIR_INST_INT_FROM_BOOL:
- instMapPut(&sema->inst_map, inst,
- zirIntFromBool(sema, block, inst));
+ instMapPut(
+ &sema->inst_map, inst, zirIntFromBool(sema, block, inst));
i++;
continue;
case ZIR_INST_NEGATE_WRAP:
- instMapPut(&sema->inst_map, inst,
- zirNegateWrap(sema, block, inst));
+ instMapPut(
+ &sema->inst_map, inst, zirNegateWrap(sema, block, inst));
i++;
continue;
@@ -4608,8 +4534,7 @@ static bool analyzeBodyInner(
// @byteSwap.
case ZIR_INST_BYTE_SWAP:
- instMapPut(&sema->inst_map, inst,
- zirByteSwap(sema, block, inst));
+ instMapPut(&sema->inst_map, inst, zirByteSwap(sema, block, inst));
i++;
continue;
@@ -4619,11 +4544,33 @@ static bool analyzeBodyInner(
i++;
continue;
+ // ret_ptr: get pointer to return value location.
+ // When inlining, emits ALLOC; otherwise emits ret_ptr.
+ // Ported from src/Sema.zig zirRetPtr.
+ case ZIR_INST_RET_PTR: {
+ TypeIndex ret_ty = sema->fn_ret_ty;
+ if (ret_ty == TYPE_NONE)
+ ret_ty = IP_INDEX_VOID_TYPE;
+ InternPoolKey pk;
+ memset(&pk, 0, sizeof(pk));
+ pk.tag = IP_KEY_PTR_TYPE;
+ pk.data.ptr_type.child = ret_ty;
+ pk.data.ptr_type.flags = 0;
+ TypeIndex ptr_ty = ipIntern(sema->ip, pk);
+ AirInstData d;
+ memset(&d, 0, sizeof(d));
+ d.ty.ty_ref = AIR_REF_FROM_IP(ptr_ty);
+ AirInstRef ref = blockAddInst(block, AIR_INST_ALLOC, d);
+ instMapPut(&sema->inst_map, inst, ref);
+ i++;
+ continue;
+ }
+
// ret_type: obtains the return type of the in-scope function.
case ZIR_INST_RET_TYPE:
if (sema->fn_ret_ty != TYPE_NONE) {
- instMapPut(&sema->inst_map, inst,
- AIR_REF_FROM_IP(sema->fn_ret_ty));
+ instMapPut(
+ &sema->inst_map, inst, AIR_REF_FROM_IP(sema->fn_ret_ty));
} else {
instMapPut(&sema->inst_map, inst,
AIR_REF_FROM_IP(IP_INDEX_VOID_TYPE));
@@ -4633,8 +4580,8 @@ static bool analyzeBodyInner(
// save_err_ret_index: no-op in ReleaseFast; map to void.
case ZIR_INST_SAVE_ERR_RET_INDEX:
- instMapPut(&sema->inst_map, inst,
- AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE));
+ instMapPut(
+ &sema->inst_map, inst, AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE));
i++;
continue;
@@ -4652,8 +4599,7 @@ static bool analyzeBodyInner(
}
TypeIndex ptr_ty = AIR_REF_TO_IP(resolved);
TypeIndex elem_ty = ptrChildType(sema->ip, ptr_ty);
- instMapPut(&sema->inst_map, inst,
- AIR_REF_FROM_IP(elem_ty));
+ instMapPut(&sema->inst_map, inst, AIR_REF_FROM_IP(elem_ty));
i++;
continue;
}
@@ -4670,8 +4616,7 @@ static bool analyzeBodyInner(
ZirInstData data = sema->code.inst_datas[inst];
uint32_t payload_index = data.pl_node.payload_index;
uint32_t inner_body_len = sema->code.extra[payload_index];
- const uint32_t* inner_body
- = &sema->code.extra[payload_index + 1];
+ const uint32_t* inner_body = &sema->code.extra[payload_index + 1];
SemaBlock ct_block;
semaBlockInit(&ct_block, sema, block);
@@ -4691,8 +4636,7 @@ static bool analyzeBodyInner(
AirInstRef result;
if (!completed) {
uint32_t break_inst = sema->comptime_break_inst;
- ZirInstData break_data
- = sema->code.inst_datas[break_inst];
+ ZirInstData break_data = sema->code.inst_datas[break_inst];
ZirInstRef operand = break_data.break_data.operand;
if (operand == ZIR_REF_NONE) {
result = AIR_REF_FROM_IP(IP_INDEX_VOID_TYPE);
@@ -4717,10 +4661,8 @@ static bool analyzeBodyInner(
ZirInstData data = sema->code.inst_datas[inst];
uint32_t payload_index = data.pl_node.payload_index;
// Payload: reason (1 word), body_len (1 word), body...
- uint32_t inner_body_len
- = sema->code.extra[payload_index + 1];
- const uint32_t* inner_body
- = &sema->code.extra[payload_index + 2];
+ uint32_t inner_body_len = sema->code.extra[payload_index + 1];
+ const uint32_t* inner_body = &sema->code.extra[payload_index + 2];
SemaBlock ct_block;
semaBlockInit(&ct_block, sema, block);
@@ -4732,8 +4674,7 @@ static bool analyzeBodyInner(
if (!completed) {
uint32_t break_inst = sema->comptime_break_inst;
- ZirInstData break_data
- = sema->code.inst_datas[break_inst];
+ ZirInstData break_data = sema->code.inst_datas[break_inst];
ZirInstRef operand = break_data.break_data.operand;
AirInstRef result;
if (operand == ZIR_REF_NONE) {
@@ -4750,15 +4691,13 @@ static bool analyzeBodyInner(
// @typeInfo(type): comptime type info extraction.
case ZIR_INST_TYPE_INFO:
- instMapPut(&sema->inst_map, inst,
- zirTypeInfoComptime(sema, inst));
+ instMapPut(&sema->inst_map, inst, zirTypeInfoComptime(sema, inst));
i++;
continue;
// @bitSizeOf(type): comptime bit size extraction.
case ZIR_INST_BIT_SIZE_OF:
- instMapPut(&sema->inst_map, inst,
- zirBitSizeOf(sema, inst));
+ instMapPut(&sema->inst_map, inst, zirBitSizeOf(sema, inst));
i++;
continue;
@@ -4771,8 +4710,7 @@ static bool analyzeBodyInner(
// field_val: comptime field access on type_info results.
case ZIR_INST_FIELD_VAL:
- instMapPut(&sema->inst_map, inst,
- zirFieldValComptime(sema, inst));
+ instMapPut(&sema->inst_map, inst, zirFieldValComptime(sema, inst));
i++;
continue;
@@ -4782,30 +4720,30 @@ static bool analyzeBodyInner(
case ZIR_INST_VALIDATE_PTR_STRUCT_INIT:
case ZIR_INST_STRUCT_INIT_FIELD_TYPE:
case ZIR_INST_STRUCT_INIT_FIELD_PTR:
- instMapPut(&sema->inst_map, inst,
- AIR_REF_FROM_IP(IP_INDEX_VOID_TYPE));
+ instMapPut(
+ &sema->inst_map, inst, AIR_REF_FROM_IP(IP_INDEX_VOID_TYPE));
i++;
continue;
// struct_init: comptime struct initialization.
case ZIR_INST_STRUCT_INIT:
- instMapPut(&sema->inst_map, inst,
- zirStructInitComptime(sema, inst));
+ instMapPut(
+ &sema->inst_map, inst, zirStructInitComptime(sema, inst));
i++;
continue;
// decl_literal: resolve enum/decl literals at comptime.
case ZIR_INST_DECL_LITERAL:
case ZIR_INST_DECL_LITERAL_NO_COERCE:
- instMapPut(&sema->inst_map, inst,
- zirDeclLiteralComptime(sema, inst));
+ instMapPut(
+ &sema->inst_map, inst, zirDeclLiteralComptime(sema, inst));
i++;
continue;
// str: string literal — map to void in comptime context.
case ZIR_INST_STR:
- instMapPut(&sema->inst_map, inst,
- AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE));
+ instMapPut(
+ &sema->inst_map, inst, AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE));
i++;
continue;
@@ -4813,8 +4751,7 @@ static bool analyzeBodyInner(
// Ported from src/Sema.zig zirAllocMut.
// Creates AIR_INST_ALLOC with pointer type *T.
case ZIR_INST_ALLOC_MUT: {
- ZirInstRef type_ref
- = sema->code.inst_datas[inst].un_node.operand;
+ ZirInstRef type_ref = sema->code.inst_datas[inst].un_node.operand;
AirInstRef resolved = resolveInst(sema, type_ref);
if (!AIR_REF_IS_IP(resolved)) {
i++;
@@ -4875,14 +4812,12 @@ static bool analyzeBodyInner(
memset(&data, 0, sizeof(data));
data.bin_op.lhs = ptr;
data.bin_op.rhs = val;
- AirInstRef store_ref
- = blockAddInst(block, AIR_INST_STORE, data);
+ AirInstRef store_ref = blockAddInst(block, AIR_INST_STORE, data);
// Track the store for the inferred alloc.
uint32_t ptr_inst = AIR_REF_TO_INST(ptr);
for (uint32_t k = 0; k < sema->num_ia; k++) {
if (sema->ia_air[k] == ptr_inst) {
- sema->ia_store[k]
- = AIR_REF_TO_INST(store_ref);
+ sema->ia_store[k] = AIR_REF_TO_INST(store_ref);
break;
}
}
@@ -4894,8 +4829,7 @@ static bool analyzeBodyInner(
// Ported from src/Sema.zig zirResolveInferredAlloc.
// Patches INFERRED_ALLOC → ALLOC with the resolved pointer type.
case ZIR_INST_RESOLVE_INFERRED_ALLOC: {
- ZirInstRef alloc_ref
- = sema->code.inst_datas[inst].un_node.operand;
+ ZirInstRef alloc_ref = sema->code.inst_datas[inst].un_node.operand;
AirInstRef ptr = resolveInst(sema, alloc_ref);
uint32_t ptr_inst = AIR_REF_TO_INST(ptr);
// Find tracked inferred alloc.
@@ -4916,8 +4850,7 @@ static bool analyzeBodyInner(
// Get the store's RHS type.
assert(sema->ia_store[ia_idx] != UINT32_MAX);
uint32_t store_inst = sema->ia_store[ia_idx];
- AirInstRef rhs
- = sema->air_inst_datas[store_inst].bin_op.rhs;
+ AirInstRef rhs = sema->air_inst_datas[store_inst].bin_op.rhs;
TypeIndex elem_ty = semaTypeOf(sema, rhs);
// Create pointer type *T (mutable, size one).
InternPoolKey key;
@@ -4965,17 +4898,79 @@ static bool analyzeBodyInner(
// block: runtime block.
// Ported from src/Sema.zig zirBlock / resolveAnalyzedBlock.
+ // In Zig, comptime .block redirects to .block_inline (no AIR
+ // BLOCK pre-allocated). We handle that here by checking
+ // is_comptime BEFORE allocating the AIR instruction.
case ZIR_INST_BLOCK: {
ZirInstData bdata = sema->code.inst_datas[inst];
uint32_t payload_index = bdata.pl_node.payload_index;
uint32_t inner_body_len = sema->code.extra[payload_index];
- const uint32_t* inner_body
- = &sema->code.extra[payload_index + 1];
+ 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, and resolveBlockBody 5906.
+ if (block->is_comptime) {
+ SemaBlockLabel label;
+ memset(&label, 0, sizeof(label));
+ label.zir_block = inst;
+ // No merges.block_inst needed (comptime breaks
+ // don't emit BR).
+
+ SemaBlock child_block;
+ semaBlockInit(&child_block, sema, block);
+ child_block.is_comptime = true;
+ child_block.want_safety = block->want_safety;
+ child_block.want_safety_set = block->want_safety_set;
+ child_block.inlining = block->inlining;
+ child_block.label = &label;
+
+ bool body_completed = analyzeBodyInner(
+ sema, &child_block, inner_body, inner_body_len);
+
+ // Copy any child instructions to parent block.
+ 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];
+ }
- // Reserve an AIR block instruction (data filled later).
- uint32_t block_inst_idx = addAirInst(sema,
- AIR_INST_BLOCK,
- (AirInstData){ .ty_pl = { .ty_ref = 0, .payload = 0 } });
+ AirInstRef result;
+ if (!body_completed && label.merges.results_len == 0) {
+ // ComptimeReturn or break to outer block:
+ // propagate upward.
+ free(label.merges.results);
+ free(label.merges.br_list);
+ semaBlockDeinit(&child_block);
+ return false;
+ } else if (!body_completed) {
+ // Break targeted this block.
+ result = label.merges.results[0];
+ } else {
+ // Body completed normally (no break).
+ result = AIR_REF_FROM_IP(IP_INDEX_UNREACHABLE_VALUE);
+ }
+
+ free(label.merges.results);
+ free(label.merges.br_list);
+ semaBlockDeinit(&child_block);
+ instMapPut(&sema->inst_map, inst, result);
+ i++;
+ continue;
+ }
+
+ // Runtime block: reserve an AIR block instruction
+ // (data filled later).
+ uint32_t block_inst_idx = addAirInst(sema, AIR_INST_BLOCK,
+ (AirInstData) { .ty_pl = { .ty_ref = 0, .payload = 0 } });
// Set up label so break instructions can find this block.
SemaBlockLabel label;
@@ -4997,42 +4992,44 @@ static bool analyzeBodyInner(
bool need_debug_scope = false;
child_block.need_debug_scope = &need_debug_scope;
- (void)analyzeBodyInner(
+ bool body_completed = analyzeBodyInner(
sema, &child_block, inner_body, inner_body_len);
// Resolve the block: write extra data and patch type.
// Ported from src/Sema.zig resolveAnalyzedBlock.
+ (void)body_completed;
AirInstRef block_result;
if (label.merges.results_len == 0) {
// No breaks (noreturn block): copy instructions to
// parent. If need_debug_scope, forward to parent.
+ // Ported from Sema.zig line 1978: isNoReturn check
+ // causes break from analyzeBodyInner loop — remaining
+ // ZIR instructions in this body are NOT processed.
if (need_debug_scope && block->need_debug_scope)
*block->need_debug_scope = true;
- for (uint32_t ci = 0;
- ci < child_block.instructions_len; ci++) {
- if (block->instructions_len
- >= block->instructions_cap) {
+ 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, new_cap * sizeof(uint32_t));
+ if (!block->instructions)
+ exit(1);
block->instructions_cap = new_cap;
}
block->instructions[block->instructions_len++]
= child_block.instructions[ci];
}
- block_result = AIR_REF_FROM_INST(
- child_block.instructions
- [child_block.instructions_len - 1]);
+ free(label.merges.results);
+ free(label.merges.br_list);
+ semaBlockDeinit(&child_block);
+ return false;
} else if (label.merges.results_len == 1) {
// Single break: check if last instruction is the
// break. Only elide if need_debug_scope is false.
// Ported from src/Sema.zig resolveAnalyzedBlock.
- uint32_t last_inst_idx
- = child_block.instructions_len - 1;
- uint32_t last_inst
- = child_block.instructions[last_inst_idx];
+ uint32_t last_inst_idx = child_block.instructions_len - 1;
+ uint32_t last_inst = child_block.instructions[last_inst_idx];
bool elide = false;
if (!need_debug_scope
&& sema->air_inst_tags[last_inst] == AIR_INST_BR
@@ -5046,12 +5043,11 @@ static bool analyzeBodyInner(
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,
+ uint32_t new_cap = block->instructions_cap * 2;
+ block->instructions = realloc(block->instructions,
new_cap * sizeof(uint32_t));
- if (!block->instructions) exit(1);
+ if (!block->instructions)
+ exit(1);
block->instructions_cap = new_cap;
}
block->instructions[block->instructions_len++]
@@ -5062,25 +5058,22 @@ static bool analyzeBodyInner(
// Need runtime block. Since result is
// comptime-known (void), use void block type.
// Emit the block instruction in the parent.
- if (block->instructions_len
- >= block->instructions_cap) {
+ 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, new_cap * sizeof(uint32_t));
+ if (!block->instructions)
+ exit(1);
block->instructions_cap = new_cap;
}
block->instructions[block->instructions_len++]
= block_inst_idx;
uint32_t extra_start
- = addAirExtra(sema,
- child_block.instructions_len);
- for (uint32_t ci = 0;
- ci < child_block.instructions_len; ci++) {
- addAirExtra(sema,
- child_block.instructions[ci]);
+ = addAirExtra(sema, child_block.instructions_len);
+ for (uint32_t ci = 0; ci < child_block.instructions_len;
+ ci++) {
+ addAirExtra(sema, child_block.instructions[ci]);
}
sema->air_inst_datas[block_inst_idx].ty_pl.ty_ref
= AIR_REF_FROM_IP(IP_INDEX_VOID_TYPE);
@@ -5088,8 +5081,7 @@ static bool analyzeBodyInner(
= extra_start;
// Rewrite the break operand to void.
- sema->air_inst_datas
- [label.merges.br_list[0]].br.operand
+ sema->air_inst_datas[label.merges.br_list[0]].br.operand
= AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
block_result = label.merges.results[0];
@@ -5097,35 +5089,81 @@ static bool analyzeBodyInner(
} else {
// Multiple breaks: need full runtime block with peer
// type resolution.
- if (block->instructions_len
- >= block->instructions_cap) {
+ 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, new_cap * sizeof(uint32_t));
+ if (!block->instructions)
+ exit(1);
block->instructions_cap = new_cap;
}
block->instructions[block->instructions_len++]
= block_inst_idx;
- TypeIndex resolved_ty = resolvePeerType(sema,
- label.merges.results[0],
- label.merges.results[1]);
+ TypeIndex resolved_ty = resolvePeerType(
+ sema, label.merges.results[0], label.merges.results[1]);
uint32_t extra_start
- = addAirExtra(sema,
- child_block.instructions_len);
- for (uint32_t ci = 0;
- ci < child_block.instructions_len; ci++) {
- addAirExtra(sema,
- child_block.instructions[ci]);
+ = addAirExtra(sema, child_block.instructions_len);
+ for (uint32_t ci = 0; ci < child_block.instructions_len;
+ ci++) {
+ addAirExtra(sema, child_block.instructions[ci]);
}
sema->air_inst_datas[block_inst_idx].ty_pl.ty_ref
= AIR_REF_FROM_IP(resolved_ty);
sema->air_inst_datas[block_inst_idx].ty_pl.payload
= extra_start;
+ // Coerce BR operands to the resolved peer type.
+ // Ported from src/Sema.zig resolveAnalyzedBlock
+ // lines 6125-6140.
+ for (uint32_t mi = 0; mi < label.merges.results_len; mi++) {
+ uint32_t br = label.merges.br_list[mi];
+ AirInstRef br_operand
+ = sema->air_inst_datas[br].br.operand;
+ TypeIndex br_ty = semaTypeOf(sema, br_operand);
+ if (br_ty == resolved_ty)
+ continue;
+ // Coerce. For constant→constant (e.g.
+ // comptime_int→concrete int), this produces
+ // no new AIR instructions.
+ SemaBlock coerce_block;
+ semaBlockInit(&coerce_block, sema, block);
+ coerce_block.is_comptime = false;
+ coerce_block.want_safety = block->want_safety;
+ coerce_block.want_safety_set = block->want_safety_set;
+ coerce_block.inlining = block->inlining;
+ AirInstRef coerced = semaCoerce(
+ sema, &coerce_block, resolved_ty, br_operand);
+ if (coerce_block.instructions_len == 0) {
+ sema->air_inst_datas[br].br.operand = coerced;
+ } else {
+ // Runtime coercion: wrap BR in
+ // a sub-block. Ported from
+ // Sema.zig lines 6141-6170.
+ assert(coerce_block
+ .instructions[coerce_block.instructions_len
+ - 1]
+ == AIR_REF_TO_INST(coerced));
+ uint32_t sub_bl = coerce_block.instructions_len + 1;
+ uint32_t sub_br_idx = addAirInst(sema, AIR_INST_BR,
+ (AirInstData) {
+ .br = { .block_inst = label.merges.block_inst,
+ .operand = coerced } });
+ uint32_t sub_extra = addAirExtra(sema, sub_bl);
+ for (uint32_t si = 0;
+ si < coerce_block.instructions_len; si++) {
+ addAirExtra(sema, coerce_block.instructions[si]);
+ }
+ addAirExtra(sema, sub_br_idx);
+ sema->air_inst_tags[br] = AIR_INST_BLOCK;
+ sema->air_inst_datas[br].ty_pl.ty_ref
+ = AIR_REF_FROM_IP(resolved_ty);
+ sema->air_inst_datas[br].ty_pl.payload = sub_extra;
+ }
+ semaBlockDeinit(&coerce_block);
+ }
+
block_result = AIR_REF_FROM_INST(block_inst_idx);
}
@@ -5145,13 +5183,9 @@ static bool analyzeBodyInner(
= (sema->code.inst_tags[inst] == ZIR_INST_BOOL_BR_OR);
uint32_t payload_index
= sema->code.inst_datas[inst].pl_node.payload_index;
- ZirInstRef lhs_ref
- = sema->code.extra[payload_index];
- uint32_t rhs_body_len
- = sema->code.extra[payload_index + 1];
- const uint32_t* rhs_body
- = &sema->code.extra[payload_index + 2];
-
+ ZirInstRef lhs_ref = sema->code.extra[payload_index];
+ uint32_t rhs_body_len = sema->code.extra[payload_index + 1];
+ const uint32_t* rhs_body = &sema->code.extra[payload_index + 2];
AirInstRef lhs = resolveInst(sema, lhs_ref);
lhs = semaCoerce(sema, block, IP_INDEX_BOOL_TYPE, lhs);
@@ -5162,8 +5196,7 @@ static bool analyzeBodyInner(
i++;
continue;
}
- if (lhs == AIR_REF_FROM_IP(IP_INDEX_BOOL_FALSE)
- && !is_bool_or) {
+ if (lhs == AIR_REF_FROM_IP(IP_INDEX_BOOL_FALSE) && !is_bool_or) {
instMapPut(&sema->inst_map, inst,
AIR_REF_FROM_IP(IP_INDEX_BOOL_FALSE));
i++;
@@ -5172,8 +5205,8 @@ static bool analyzeBodyInner(
// Comptime-known LHS, evaluate RHS body on parent block.
if (lhs == AIR_REF_FROM_IP(IP_INDEX_BOOL_TRUE)
|| lhs == AIR_REF_FROM_IP(IP_INDEX_BOOL_FALSE)) {
- bool completed = analyzeBodyInner(
- sema, block, rhs_body, rhs_body_len);
+ bool completed
+ = analyzeBodyInner(sema, block, rhs_body, rhs_body_len);
AirInstRef rhs_result;
if (!completed) {
uint32_t bi = sema->comptime_break_inst;
@@ -5183,19 +5216,18 @@ static bool analyzeBodyInner(
} else {
rhs_result = AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
}
- rhs_result = semaCoerce(
- sema, block, IP_INDEX_BOOL_TYPE, rhs_result);
+ rhs_result
+ = semaCoerce(sema, block, IP_INDEX_BOOL_TYPE, rhs_result);
instMapPut(&sema->inst_map, inst, rhs_result);
i++;
continue;
}
// Runtime: emit BLOCK(bool) + COND_BR with then/else bodies.
- uint32_t block_inst_idx = addAirInst(sema,
- AIR_INST_BLOCK,
- (AirInstData){ .ty_pl = {
- .ty_ref = AIR_REF_FROM_IP(IP_INDEX_BOOL_TYPE),
- .payload = 0 } });
+ uint32_t block_inst_idx = addAirInst(sema, AIR_INST_BLOCK,
+ (AirInstData) {
+ .ty_pl = { .ty_ref = AIR_REF_FROM_IP(IP_INDEX_BOOL_TYPE),
+ .payload = 0 } });
SemaBlockLabel label;
memset(&label, 0, sizeof(label));
@@ -5204,7 +5236,8 @@ static bool analyzeBodyInner(
SemaBlock child_block;
semaBlockInit(&child_block, sema, block);
- child_block.is_comptime = false;
+ // Inherit comptime from parent (matches Zig Sema.zig).
+ child_block.is_comptime = block->is_comptime;
child_block.want_safety = block->want_safety;
child_block.want_safety_set = block->want_safety_set;
child_block.inlining = block->inlining;
@@ -5229,10 +5262,8 @@ static bool analyzeBodyInner(
else_block.label = child_block.label;
else_block.need_debug_scope = NULL;
- SemaBlock* lhs_block
- = is_bool_or ? &then_block : &else_block;
- SemaBlock* rhs_block
- = is_bool_or ? &else_block : &then_block;
+ SemaBlock* lhs_block = is_bool_or ? &then_block : &else_block;
+ SemaBlock* rhs_block = is_bool_or ? &else_block : &then_block;
// LHS block: emit BR with short-circuit result.
AirInstRef lhs_result = is_bool_or
@@ -5245,8 +5276,8 @@ static bool analyzeBodyInner(
br_data.br.operand = lhs_result;
AirInstRef br_ref
= blockAddInst(lhs_block, AIR_INST_BR, br_data);
- mergesAppend(&label.merges,
- lhs_result, AIR_REF_TO_INST(br_ref));
+ mergesAppend(
+ &label.merges, lhs_result, AIR_REF_TO_INST(br_ref));
}
// Save/restore branch hint across RHS body.
@@ -5254,8 +5285,8 @@ static bool analyzeBodyInner(
sema->branch_hint = -1;
// RHS block: evaluate body (ends with break_inline).
- bool rhs_completed = analyzeBodyInner(
- sema, rhs_block, rhs_body, rhs_body_len);
+ bool rhs_completed
+ = analyzeBodyInner(sema, rhs_block, rhs_body, rhs_body_len);
AirInstRef rhs_result;
if (!rhs_completed) {
uint32_t bi = sema->comptime_break_inst;
@@ -5265,8 +5296,8 @@ static bool analyzeBodyInner(
} else {
rhs_result = AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
}
- rhs_result = semaCoerce(
- sema, rhs_block, IP_INDEX_BOOL_TYPE, rhs_result);
+ rhs_result
+ = semaCoerce(sema, rhs_block, IP_INDEX_BOOL_TYPE, rhs_result);
// Emit BR for RHS result.
{
@@ -5276,12 +5307,12 @@ static bool analyzeBodyInner(
br_data.br.operand = rhs_result;
AirInstRef br_ref
= blockAddInst(rhs_block, AIR_INST_BR, br_data);
- mergesAppend(&label.merges,
- rhs_result, AIR_REF_TO_INST(br_ref));
+ mergesAppend(
+ &label.merges, rhs_result, AIR_REF_TO_INST(br_ref));
}
- uint8_t rhs_hint = (sema->branch_hint >= 0)
- ? (uint8_t)sema->branch_hint : 0;
+ uint8_t rhs_hint
+ = (sema->branch_hint >= 0) ? (uint8_t)sema->branch_hint : 0;
sema->branch_hint = parent_hint;
// Emit COND_BR in child_block.
@@ -5301,12 +5332,10 @@ static bool analyzeBodyInner(
branch_hints_packed |= (1u << 7); // else_cov = poi
addAirExtra(sema, branch_hints_packed);
- for (uint32_t ti = 0;
- ti < then_block.instructions_len; ti++) {
+ for (uint32_t ti = 0; ti < then_block.instructions_len; ti++) {
addAirExtra(sema, then_block.instructions[ti]);
}
- for (uint32_t ei = 0;
- ei < else_block.instructions_len; ei++) {
+ for (uint32_t ei = 0; ei < else_block.instructions_len; ei++) {
addAirExtra(sema, else_block.instructions[ei]);
}
@@ -5314,26 +5343,23 @@ static bool analyzeBodyInner(
memset(&cond_data, 0, sizeof(cond_data));
cond_data.pl_op.operand = lhs;
cond_data.pl_op.payload = extra_start;
- (void)blockAddInst(
- &child_block, AIR_INST_COND_BR, cond_data);
+ (void)blockAddInst(&child_block, AIR_INST_COND_BR, cond_data);
// Resolve the block (same as zirBlock resolveAnalyzedBlock).
// bool_br always has 2 merges (lhs + rhs BR).
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
+ = 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;
+ block->instructions[block->instructions_len++] = block_inst_idx;
uint32_t blk_extra_start
= addAirExtra(sema, child_block.instructions_len);
- for (uint32_t ci = 0;
- ci < child_block.instructions_len; ci++) {
+ for (uint32_t ci = 0; ci < child_block.instructions_len; ci++) {
addAirExtra(sema, child_block.instructions[ci]);
}
sema->air_inst_datas[block_inst_idx].ty_pl.payload
@@ -5344,8 +5370,8 @@ static bool analyzeBodyInner(
semaBlockDeinit(&else_block);
semaBlockDeinit(&then_block);
semaBlockDeinit(&child_block);
- instMapPut(&sema->inst_map, inst,
- AIR_REF_FROM_INST(block_inst_idx));
+ instMapPut(
+ &sema->inst_map, inst, AIR_REF_FROM_INST(block_inst_idx));
i++;
continue;
}
@@ -5355,28 +5381,24 @@ static bool analyzeBodyInner(
case ZIR_INST_CONDBR: {
uint32_t payload_index
= sema->code.inst_datas[inst].pl_node.payload_index;
- ZirInstRef condition_ref
- = sema->code.extra[payload_index];
- uint32_t then_body_len
- = sema->code.extra[payload_index + 1];
- uint32_t else_body_len
- = sema->code.extra[payload_index + 2];
- const uint32_t* then_body
- = &sema->code.extra[payload_index + 3];
+ ZirInstRef condition_ref = sema->code.extra[payload_index];
+ uint32_t then_body_len = sema->code.extra[payload_index + 1];
+ uint32_t else_body_len = sema->code.extra[payload_index + 2];
+ const uint32_t* then_body = &sema->code.extra[payload_index + 3];
const uint32_t* else_body
= &sema->code.extra[payload_index + 3 + then_body_len];
- AirInstRef cond = resolveInst(sema, condition_ref);
+ AirInstRef uncasted_cond = resolveInst(sema, condition_ref);
+ AirInstRef cond
+ = semaCoerce(sema, block, IP_INDEX_BOOL_TYPE, uncasted_cond);
// Comptime-known condition: only analyze the taken branch
// on the parent block (matches Zig sema line 18343-18353).
if (cond == AIR_REF_FROM_IP(IP_INDEX_BOOL_TRUE)) {
- return analyzeBodyInner(
- sema, block, then_body, then_body_len);
+ return analyzeBodyInner(sema, block, then_body, then_body_len);
}
if (cond == AIR_REF_FROM_IP(IP_INDEX_BOOL_FALSE)) {
- return analyzeBodyInner(
- sema, block, else_body, else_body_len);
+ return analyzeBodyInner(sema, block, else_body, else_body_len);
}
// Analyze then-body in a sub-block, collecting branch hint.
@@ -5405,8 +5427,6 @@ static bool analyzeBodyInner(
else_block.need_debug_scope = NULL;
uint8_t false_hint = analyzeBodyRuntimeBreak(
sema, &else_block, else_body, else_body_len);
-
- // Emit AIR_INST_COND_BR.
// Extra data: {then_body_len, else_body_len, branch_hints,
// then_body[...], else_body[...]}
uint32_t extra_start
@@ -5425,12 +5445,10 @@ static bool analyzeBodyInner(
branch_hints_packed |= (1u << 7); // else_cov = poi
addAirExtra(sema, branch_hints_packed);
- for (uint32_t ti = 0;
- ti < then_block.instructions_len; ti++) {
+ for (uint32_t ti = 0; ti < then_block.instructions_len; ti++) {
addAirExtra(sema, then_block.instructions[ti]);
}
- for (uint32_t ei = 0;
- ei < else_block.instructions_len; ei++) {
+ for (uint32_t ei = 0; ei < else_block.instructions_len; ei++) {
addAirExtra(sema, else_block.instructions[ei]);
}
@@ -5468,17 +5486,22 @@ static bool analyzeBodyInner(
continue;
}
+ if (block->is_comptime) {
+ // Comptime break: record result without emitting BR.
+ // Ported from src/Sema.zig zirBreak comptime path.
+ mergesAppend(&label->merges, operand, 0);
+ return false;
+ }
+
// Emit AIR br instruction.
AirInstData br_data;
memset(&br_data, 0, sizeof(br_data));
br_data.br.block_inst = label->merges.block_inst;
br_data.br.operand = operand;
- AirInstRef br_ref
- = blockAddInst(block, AIR_INST_BR, br_data);
+ AirInstRef br_ref = blockAddInst(block, AIR_INST_BR, br_data);
// Record merge result.
- mergesAppend(&label->merges,
- operand, AIR_REF_TO_INST(br_ref));
+ mergesAppend(&label->merges, operand, AIR_REF_TO_INST(br_ref));
return false; // break is terminal
}
@@ -5488,8 +5511,7 @@ static bool analyzeBodyInner(
// unreach.
case ZIR_INST_PANIC: {
// Resolve the string message operand.
- ZirInstRef msg_ref
- = sema->code.inst_datas[inst].un_node.operand;
+ ZirInstRef msg_ref = sema->code.inst_datas[inst].un_node.operand;
AirInstRef msg = resolveInst(sema, msg_ref);
(void)msg; // msg used in call args below
@@ -5551,13 +5573,12 @@ static bool analyzeBodyInner(
// Saves/restores the parent hint, resets hint for the body,
// returns the collected hint (0=none if no @branchHint was set).
static uint8_t analyzeBodyRuntimeBreak(
- Sema* sema, SemaBlock* block,
- const uint32_t* body, uint32_t body_len) {
+ Sema* sema, SemaBlock* block, const uint32_t* body, uint32_t body_len) {
int8_t parent_hint = sema->branch_hint;
sema->branch_hint = -1;
- (void)analyzeBodyInner(sema, block, body, body_len);
- uint8_t result = (sema->branch_hint >= 0)
- ? (uint8_t)sema->branch_hint : 0;
+ bool inner_ok = analyzeBodyInner(sema, block, body, body_len);
+ (void)inner_ok;
+ uint8_t result = (sema->branch_hint >= 0) ? (uint8_t)sema->branch_hint : 0;
sema->branch_hint = parent_hint;
return result;
}
diff --git a/stage0/sema.h b/stage0/sema.h
@@ -51,6 +51,7 @@ typedef struct SemaBlockInlining {
InternPoolIndex func;
bool is_generic_instantiation;
bool has_comptime_args;
+ bool comptime_returned;
AirInstRef comptime_result;
SemaBlockMerges merges;
} SemaBlockInlining;
diff --git a/stage0/sema_test.zig b/stage0/sema_test.zig
@@ -233,7 +233,8 @@ extern fn zig_compile_air([*:0]const u8, ?[*:0]const u8, [*]u8) ZigCompileAirRes
extern fn zig_compile_air_free(*ZigCompileAirResult) void;
pub fn airCompareFromSource(source: [:0]const u8, c_func_air_list: c.SemaFuncAirList) !void {
- const tmp_path = "/tmp/zig0_sema_test_tmp.zig";
+ var buf: [64]u8 = undefined;
+ const tmp_path = std.fmt.bufPrintZ(&buf, "/tmp/zig0_sema_{d}.zig", .{std.os.linux.getpid()}) catch unreachable;
{
const f = std.fs.cwd().createFile(tmp_path, .{}) catch return error.TmpFileCreate;
defer f.close();
@@ -498,6 +499,10 @@ fn airDataRefSlots(tag_val: u8) [2]bool {
=> .{ true, true },
// arg: type(Ref) + zir_param_index(u32)
c.AIR_INST_ARG => .{ true, false },
+ // br: block_inst(u32) + operand(Ref)
+ c.AIR_INST_BR => .{ false, true },
+ // pl_op (cond_br): operand(Ref) + payload(u32)
+ c.AIR_INST_COND_BR => .{ true, false },
// Default: assume no refs (compare directly).
// If a tag with refs is missed, the comparison will fail
// and we add it here.
@@ -600,18 +605,23 @@ fn airCompareOne(name: []const u8, zig_air: *const c.Air, c_air: *const c.Air) !
const zig_word = std.mem.readInt(u32, zig_datas[s..][0..4], .little);
const c_word = std.mem.readInt(u32, c_datas[s..][0..4], .little);
+ // Skip data comparison for dead BLOCKs (tag 51).
+ // Dead BLOCKs have undefined data in Zig (0xaa..
+ // or stale values) vs zeroed in C.
+ if (tag_val == 51 and c_word == 0 and zig_word != 0) continue;
+
if (ref_slots[slot]) {
// This slot is a Ref — canonicalize IP refs.
const zig_canon = canonicalizeRef(zig_word, &zig_ref_map, &next_zig_id);
const c_canon = canonicalizeRef(c_word, &c_ref_map, &next_c_id);
if (zig_canon != c_canon) {
- std.debug.print("'{s}': datas ref mismatch at inst[{d}] slot {d}: zig=0x{x} c=0x{x} (canon: zig={d} c={d})\n", .{ name, j, slot, zig_word, c_word, zig_canon, c_canon });
+ std.debug.print("'{s}': datas ref mismatch at inst[{d}] slot {d}: zig=0x{x} c=0x{x} (canon: zig={d} c={d}) (tag={d})\n", .{ name, j, slot, zig_word, c_word, zig_canon, c_canon, tag_val });
return error.AirMismatch;
}
} else {
// Non-ref field — compare directly.
if (zig_word != c_word) {
- std.debug.print("'{s}': datas mismatch at inst[{d}] slot {d}: zig=0x{x} c=0x{x}\n", .{ name, j, slot, zig_word, c_word });
+ std.debug.print("'{s}': datas mismatch at inst[{d}] slot {d}: zig=0x{x} c=0x{x} (tag={d})\n", .{ name, j, slot, zig_word, c_word, tag_val });
return error.AirMismatch;
}
}
@@ -622,6 +632,36 @@ fn airCompareOne(name: []const u8, zig_air: *const c.Air, c_air: *const c.Air) !
// Extra
if (zig_air.extra_len != c_air.extra_len) {
std.debug.print("'{s}': extra_len mismatch: zig={d} c={d}\n", .{ name, zig_air.extra_len, c_air.extra_len });
+ // Print first divergence point
+ const min_len = @min(zig_air.extra_len, c_air.extra_len);
+ if (min_len > 0) {
+ const zig_e: [*]const u32 = cToOpt(u32, zig_air.extra).?;
+ const c_e: [*]const u32 = cToOpt(u32, c_air.extra).?;
+ var printed: u32 = 0;
+ for (0..min_len) |ei| {
+ if (zig_e[ei] != c_e[ei] and printed < 40) {
+ std.debug.print(" extra[{d}]: zig={d} c={d}\n", .{ ei, zig_e[ei], c_e[ei] });
+ printed += 1;
+ }
+ }
+ // Also dump the raw extra arrays around the first divergence
+ var first_diff: usize = min_len;
+ for (0..min_len) |ei| {
+ if (zig_e[ei] != c_e[ei]) {
+ first_diff = ei;
+ break;
+ }
+ }
+ if (first_diff < min_len) {
+ const start = if (first_diff > 5) first_diff - 5 else 0;
+ const end = @min(first_diff + 20, min_len);
+ std.debug.print(" zig extra[{d}..{d}]:", .{ start, end });
+ for (start..end) |ei| std.debug.print(" {d}", .{zig_e[ei]});
+ std.debug.print("\n c extra[{d}..{d}]:", .{ start, end });
+ for (start..end) |ei| std.debug.print(" {d}", .{c_e[ei]});
+ std.debug.print("\n", .{});
+ }
+ }
return error.AirMismatch;
}
const extra_len = zig_air.extra_len;
diff --git a/stage0/stages_test.zig b/stage0/stages_test.zig
@@ -61,7 +61,11 @@ fn stagesCheck(gpa: Allocator, comptime path: []const u8, source: [:0]const u8)
// the module root, while keeping logical paths under .zig-cache/tmp/
// to avoid 'std' module conflicts with lib/std/.
const this_dir = comptime std.fs.path.dirname(@src().file) orelse ".";
- const symlink_path = ".zig-cache/tmp/zig0_test";
+
+ // Use PID-based symlink path to avoid races when all-zig0 runs
+ // multiple compilers in parallel.
+ var symlink_buf: [64:0]u8 = undefined;
+ const symlink_path = std.fmt.bufPrintZ(&symlink_buf, ".zig-cache/tmp/zig0_test_{d}", .{std.os.linux.getpid()}) catch unreachable;
// All corpus paths start with "../"; strip to get repo-relative path.
const repo_relative = comptime blk: {
@@ -79,7 +83,8 @@ fn stagesCheck(gpa: Allocator, comptime path: []const u8, source: [:0]const u8)
// Compute source directory for import resolution.
const repo_dir = comptime std.fs.path.dirname(repo_relative) orelse ".";
- const source_dir_path: [:0]const u8 = symlink_path ++ "/" ++ repo_dir;
+ var source_dir_buf: [128:0]u8 = undefined;
+ const source_dir_path = std.fmt.bufPrintZ(&source_dir_buf, "{s}/{s}", .{ symlink_path, repo_dir }) catch unreachable;
var c_ip = sc.ipInit();
defer sc.ipDeinit(&c_ip);
@@ -90,9 +95,9 @@ fn stagesCheck(gpa: Allocator, comptime path: []const u8, source: [:0]const u8)
var c_func_air_list = sc.semaAnalyze(&c_sema);
defer sc.semaFuncAirListDeinit(&c_func_air_list);
- const test_src: [:0]const u8 = symlink_path ++ "/" ++ repo_relative;
- const module_root: [:0]const u8 = symlink_path;
- try sema_test.airCompare(test_src.ptr, module_root.ptr, c_func_air_list);
+ var test_src_buf: [256:0]u8 = undefined;
+ const test_src = std.fmt.bufPrintZ(&test_src_buf, "{s}/{s}", .{ symlink_path, repo_relative }) catch unreachable;
+ try sema_test.airCompare(test_src.ptr, symlink_path.ptr, c_func_air_list);
}
}
@@ -108,7 +113,7 @@ const corpus_files = .{
"../lib/compiler_rt/absvdi2.zig", // 311 -- needs alloc_mut, block, condbr, panic, call
"../lib/compiler_rt/absvsi2.zig", // 311
"../lib/compiler_rt/absvti2.zig", // 314
- //"../lib/compiler_rt/addhf3.zig", // 319 -- needs @import, need_debug_scope/ensurePostHoc phantom blocks
+ "../lib/compiler_rt/addhf3.zig", // 319
//"../lib/compiler_rt/addxf3.zig", // 323
//"../lib/compiler_rt/mulhf3.zig", // 323
//"../lib/compiler_rt/mulxf3.zig", // 323