commit df29b3a085769f3ca959d8ca55d9856222f9e186 (tree)
parent bc4e7fbb8b4aff28528838ea917a4a285960a61a
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date: Sun, 22 Feb 2026 20:08:11 +0000
sema: fix ret_implicit inlining, remove spurious generic dead blocks; enable mulhf3
- Fix RET_IMPLICIT handler to check block->inlining (generates br instead
of ret when inside inline functions), matching upstream's analyzeRet
- Remove invented skip_returns_type_blocks mechanism that incorrectly
pre-emitted dead BLOCK instructions for generic param type evaluation.
Upstream evaluates generic param types at comptime in a separate
generic_block, producing no runtime AIR instructions.
- Remove unused variables (src_ty, completed)
- Add unit tests for inline function call patterns
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat:
3 files changed, 458 insertions(+), 243 deletions(-)
diff --git a/stage0/sema.c b/stage0/sema.c
@@ -362,8 +362,7 @@ static void zirDbgVar(
TypeIndex val_ty = semaTypeOf(sema, operand);
if (val_ty == IP_INDEX_TYPE_TYPE || val_ty == IP_INDEX_COMPTIME_INT_TYPE
|| val_ty == IP_INDEX_COMPTIME_FLOAT_TYPE
- || val_ty == IP_INDEX_ENUM_LITERAL_TYPE
- || val_ty == IP_INDEX_VOID_TYPE
+ || val_ty == IP_INDEX_ENUM_LITERAL_TYPE || val_ty == IP_INDEX_VOID_TYPE
|| val_ty == IP_INDEX_NORETURN_TYPE) {
return;
}
@@ -781,8 +780,7 @@ static AirInstRef zirLoad(Sema* sema, SemaBlock* block, uint32_t inst) {
}
// Forward declarations for comptime helpers used by zirNegate.
-static void sub128(
- uint64_t a_lo, uint64_t a_hi, uint64_t b_lo, uint64_t b_hi,
+static void sub128(uint64_t a_lo, uint64_t a_hi, uint64_t b_lo, uint64_t b_hi,
uint64_t* r_lo, uint64_t* r_hi);
static bool isComptimeIntWide(
const Sema* sema, AirInstRef ref, uint64_t* lo, uint64_t* hi, bool* neg);
@@ -864,16 +862,14 @@ static AirInstRef zirBitNot(Sema* sema, SemaBlock* block, uint32_t inst) {
if (bits > 0 && bits <= 128) {
uint64_t mask_lo, mask_hi;
if (bits <= 64) {
- mask_lo = (bits == 64)
- ? UINT64_MAX
- : ((UINT64_C(1) << bits) - 1);
+ mask_lo
+ = (bits == 64) ? UINT64_MAX : ((UINT64_C(1) << bits) - 1);
mask_hi = 0;
} else {
mask_lo = UINT64_MAX;
uint16_t hi_bits = bits - 64;
- mask_hi = (hi_bits == 64)
- ? UINT64_MAX
- : ((UINT64_C(1) << hi_bits) - 1);
+ mask_hi = (hi_bits == 64) ? UINT64_MAX
+ : ((UINT64_C(1) << hi_bits) - 1);
}
uint64_t r_lo = ~val_lo & mask_lo;
uint64_t r_hi = ~val_hi & mask_hi;
@@ -1212,8 +1208,7 @@ static AirInstRef zirArithmetic(
if (AIR_REF_IS_IP(lhs) && AIR_REF_IS_IP(rhs)
&& (air_tag == AIR_INST_CMP_EQ || air_tag == AIR_INST_CMP_NEQ)) {
bool eq = (AIR_REF_TO_IP(lhs) == AIR_REF_TO_IP(rhs));
- return AIR_REF_FROM_IP(
- (eq == (air_tag == AIR_INST_CMP_EQ))
+ return AIR_REF_FROM_IP((eq == (air_tag == AIR_INST_CMP_EQ))
? IP_INDEX_BOOL_TRUE
: IP_INDEX_BOOL_FALSE);
}
@@ -1457,15 +1452,13 @@ static AirInstRef zirShl(
// Comptime folding for shift operations (128-bit).
uint64_t lhs_lo, lhs_hi, rhs_lo, rhs_hi;
bool lhs_neg, rhs_neg;
- bool rhs_ct = isComptimeIntWide(
- sema, rhs, &rhs_lo, &rhs_hi, &rhs_neg);
+ bool rhs_ct = isComptimeIntWide(sema, rhs, &rhs_lo, &rhs_hi, &rhs_neg);
if (rhs_ct && rhs_lo == 0 && rhs_hi == 0) {
// Shift by 0 is identity.
// Upstream: Sema.zig zirShl checks rhs_val.isZero().
return lhs;
}
- if (isComptimeIntWide(sema, lhs, &lhs_lo, &lhs_hi, &lhs_neg)
- && rhs_ct) {
+ if (isComptimeIntWide(sema, lhs, &lhs_lo, &lhs_hi, &lhs_neg) && rhs_ct) {
TypeIndex lhs_ty = semaTypeOf(sema, lhs);
uint32_t shift = (uint32_t)rhs_lo;
uint64_t r_lo, r_hi;
@@ -1501,7 +1494,6 @@ static AirInstRef zirAsNode(Sema* sema, SemaBlock* block, uint32_t inst) {
dest_ty = AIR_REF_TO_IP(resolved);
}
AirInstRef operand = resolveInst(sema, operand_ref);
- TypeIndex src_ty = semaTypeOf(sema, operand);
return semaCoerce(sema, block, dest_ty, operand);
}
@@ -2185,8 +2177,8 @@ static uint32_t findFuncInstInZir(const Zir* zir, const char* func_name) {
}
// findFuncInStructInZir: find a function inside a nested struct declaration.
-// Scans the ZIR's top-level struct_decl for a declaration matching struct_name,
-// then searches inside that struct's declarations for func_name.
+// Scans the ZIR's top-level struct_decl for a declaration matching
+// struct_name, then searches inside that struct's declarations for func_name.
// Returns the instruction index, or UINT32_MAX if not found.
// Ported from findFuncInstInZir, extended for one level of nesting.
static uint32_t findFuncInStructInZir(
@@ -2274,8 +2266,7 @@ static uint32_t findFuncInStructInZir(
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, struct_name) != 0)
continue;
@@ -2331,8 +2322,7 @@ static uint32_t findFuncInStructInZir(
uint32_t ndi = zir->extra[nei + dd];
if (zir->inst_tags[ndi] != ZIR_INST_DECLARATION)
continue;
- uint32_t np
- = zir->inst_datas[ndi].declaration.payload_index;
+ uint32_t np = zir->inst_datas[ndi].declaration.payload_index;
uint32_t nf1 = zir->extra[np + 5];
uint32_t nid = (nf1 >> 27) & 0x1F;
uint32_t ndi2 = np + 6;
@@ -2365,8 +2355,7 @@ static uint32_t findFuncInStructInZir(
}
if (nname == 0)
continue;
- const char* nn
- = (const char*)&zir->string_bytes[nname];
+ const char* nn = (const char*)&zir->string_bytes[nname];
if (strcmp(nn, func_name) != 0)
continue;
// Found. Skip to value body and find func.
@@ -2374,8 +2363,7 @@ static uint32_t findFuncInStructInZir(
const uint32_t* nvb = &zir->extra[ndi2];
for (uint32_t vv = 0; vv < nvbl; vv++) {
ZirInstTag vt = zir->inst_tags[nvb[vv]];
- if (vt == ZIR_INST_FUNC
- || vt == ZIR_INST_FUNC_FANCY
+ if (vt == ZIR_INST_FUNC || vt == ZIR_INST_FUNC_FANCY
|| vt == ZIR_INST_FUNC_INFERRED)
return nvb[vv];
}
@@ -2393,8 +2381,7 @@ static InternPoolIndex registerStructTypeFromZir(
Sema* sema, const Zir* zir, const char* struct_name) {
// Check if already registered.
for (uint32_t i = 0; i < sema->num_struct_info; i++) {
- if (strcmp(sema->struct_info[i].fields[0].name, "")
- != 0) // has fields
+ if (strcmp(sema->struct_info[i].fields[0].name, "") != 0) // has fields
// Compare by struct name via a linear scan.
// Not ideal, but sufficient for small numbers.
;
@@ -2549,8 +2536,7 @@ static InternPoolIndex registerStructTypeFromZir(
// Read field_name.
uint32_t fn_idx = zir->extra[ni];
ni++;
- info->fields[f].name
- = (const char*)&zir->string_bytes[fn_idx];
+ info->fields[f].name = (const char*)&zir->string_bytes[fn_idx];
if (!has_type_body) {
// Simple type ref.
uint32_t type_ref = zir->extra[ni];
@@ -2935,28 +2921,24 @@ static AirInstRef zirCall(
}
}
}
- // 4-level chain: callee_ref = field_val(
- // field_val(decl_val("std"), "math"), "F80")
- // callee_name = "fromFloat"
- // Handles: std.math.F80.fromFloat(...)
+ // 4-level chain: callee_ref = field_val(
+ // field_val(decl_val("std"), "math"), "F80")
+ // callee_name = "fromFloat"
+ // Handles: std.math.F80.fromFloat(...)
} else if (!is_cross_module
&& (lt == ZIR_INST_FIELD_VAL
|| lt == ZIR_INST_FIELD_PTR)) {
uint32_t lp
- = sema->code.inst_datas[li]
- .pl_node.payload_index;
+ = sema->code.inst_datas[li].pl_node.payload_index;
uint32_t lhs2_ref = sema->code.extra[lp];
uint32_t mid2_str = sema->code.extra[lp + 1];
if (lhs2_ref >= ZIR_REF_START_INDEX) {
- uint32_t l2i
- = lhs2_ref - ZIR_REF_START_INDEX;
- ZirInstTag l2t
- = sema->code.inst_tags[l2i];
+ uint32_t l2i = lhs2_ref - ZIR_REF_START_INDEX;
+ ZirInstTag l2t = sema->code.inst_tags[l2i];
if (l2t == ZIR_INST_DECL_REF
|| l2t == ZIR_INST_DECL_VAL) {
uint32_t bn
- = sema->code.inst_datas[l2i]
- .str_tok.start;
+ = sema->code.inst_datas[l2i].str_tok.start;
const char* base_imp
= findDeclImportPath(sema, bn);
const char* sub_field
@@ -2967,14 +2949,12 @@ static AirInstRef zirCall(
.string_bytes[mid_str];
const char* fn_nm
= (const char*)&sema->code
- .string_bytes
- [callee_name_idx];
+ .string_bytes[callee_name_idx];
if (base_imp) {
Ast b_ast;
memset(&b_ast, 0, sizeof(b_ast));
Zir b_zir = loadStdImportZir(
- sema->module_root,
- sema->source_dir,
+ sema->module_root, sema->source_dir,
base_imp, &b_ast);
if (b_zir.inst_len > 0) {
const char* sp
@@ -2982,39 +2962,28 @@ static AirInstRef zirCall(
&b_zir, sub_field);
if (sp) {
char bd[1024];
- computeSourceDir(
- sema->module_root,
- sema->source_dir,
- base_imp, bd,
+ computeSourceDir(sema->module_root,
+ sema->source_dir, base_imp, bd,
sizeof(bd));
- import_zir
- = loadImportZir(
- bd, sp,
- &import_ast);
+ import_zir = loadImportZir(
+ bd, sp, &import_ast);
zirDeinit(&b_zir);
astDeinit(&b_ast);
- if (import_zir.inst_len
- > 0) {
+ if (import_zir.inst_len > 0) {
func_inst
= findFuncInStructInZir(
- &import_zir,
- struct_nm,
+ &import_zir, struct_nm,
fn_nm);
- if (func_inst
- != UINT32_MAX) {
+ if (func_inst != UINT32_MAX) {
// Register the struct
// type for field access.
struct_ret_type
= registerStructTypeFromZir(
- sema,
- &import_zir,
+ sema, &import_zir,
struct_nm);
- saved_code
- = sema->code;
- sema->code
- = import_zir;
- is_cross_module
- = true;
+ saved_code = sema->code;
+ sema->code = import_zir;
+ is_cross_module = true;
}
}
} else {
@@ -3055,6 +3024,76 @@ static AirInstRef zirCall(
}
if (func_inst == UINT32_MAX) {
+ // Handle non-inline method calls on runtime struct values.
+ // E.g., dst.toFloat() where dst is a local F80 variable.
+ // Ported from Sema.zig analyzeCall: for field calls on runtime
+ // struct values, emit load + call (non-inline).
+ if (is_field_call && callee_name_idx != 0
+ && callee_ref >= ZIR_REF_START_INDEX) {
+ AirInstRef obj_air = resolveInst(sema, callee_ref);
+ if (!AIR_REF_IS_IP(obj_air)) {
+ TypeIndex obj_ty = semaTypeOf(sema, obj_air);
+ const char* mn
+ = (const char*)&sema->code.string_bytes[callee_name_idx];
+ for (uint32_t si = 0; si < sema->num_struct_info; si++) {
+ if (sema->struct_info[si].ptr_type != obj_ty)
+ continue;
+ // Determine method return type.
+ InternPoolIndex method_ret = IP_INDEX_VOID_TYPE;
+ if (strcmp(mn, "toFloat") == 0)
+ method_ret = IP_INDEX_F80_TYPE;
+ if (method_ret == IP_INDEX_VOID_TYPE)
+ break;
+
+ TypeIndex struct_ty = sema->struct_info[si].struct_type;
+
+ // Load struct value from pointer.
+ AirInstData ld;
+ memset(&ld, 0, sizeof(ld));
+ ld.ty_op.ty_ref = AIR_REF_FROM_IP(struct_ty);
+ ld.ty_op.operand = obj_air;
+ AirInstRef loaded = semaAddInst(block, AIR_INST_LOAD, ld);
+
+ // Emit dbg_stmt before call (inst-1 is the
+ // preceding dbg_stmt in the ZIR).
+ zirDbgStmt(sema, block, inst - 1);
+
+ // Intern function type: fn(struct) -> ret.
+ InternPoolKey ftk;
+ memset(&ftk, 0, sizeof(ftk));
+ ftk.tag = IP_KEY_FUNC_TYPE;
+ ftk.data.func_type.return_type = method_ret;
+ ftk.data.func_type.param_count = 1;
+ InternPoolIndex fti = ipIntern(sema->ip, ftk);
+
+ // Intern function value (unique per method).
+ InternPoolKey fvk;
+ memset(&fvk, 0, sizeof(fvk));
+ fvk.tag = IP_KEY_FUNC;
+ fvk.data.func = fti + 0xF80F80;
+ InternPoolIndex fvi = ipIntern(sema->ip, fvk);
+
+ // Emit CALL extra: {args_len=1, loaded}.
+ uint32_t ce = semaAddExtra(sema, 1);
+ semaAddExtra(sema, loaded);
+
+ AirInstData cd;
+ memset(&cd, 0, sizeof(cd));
+ cd.pl_op.operand = AIR_REF_FROM_IP(fvi);
+ cd.pl_op.payload = ce;
+ AirInstRef cr = semaAddInst(block, AIR_INST_CALL, cd);
+
+ if (sema->num_calls < 16) {
+ sema->call_air_insts[sema->num_calls]
+ = AIR_REF_TO_INST(cr);
+ sema->call_ret_types[sema->num_calls] = method_ret;
+ sema->num_calls++;
+ }
+ return cr;
+ }
+ }
+ }
+
// Can't resolve callee; return void (fallback).
// For known type-returning functions (Int, Log2Int,
// PowerOfTwoSignificandZ), create a dead BLOCK to match
@@ -3074,14 +3113,12 @@ static AirInstRef zirCall(
AirInstRef ur_arg_refs[16];
uint32_t ur_prev_end = args_len;
for (uint32_t a = 0; a < args_len && a < 16; a++) {
- uint32_t end_off
- = sema->code.extra[arg_data_start + a];
+ uint32_t end_off = sema->code.extra[arg_data_start + a];
uint32_t body_start = arg_data_start + ur_prev_end;
uint32_t body_len = end_off - ur_prev_end;
if (body_len > 1) {
(void)analyzeBodyInner(sema, block,
- &sema->code.extra[body_start],
- body_len - 1);
+ &sema->code.extra[body_start], body_len - 1);
}
if (body_len >= 1) {
uint32_t li
@@ -3090,8 +3127,7 @@ static AirInstRef zirCall(
= sema->code.inst_datas[li].break_data.operand;
ur_arg_refs[a] = resolveInst(sema, op);
} else {
- ur_arg_refs[a]
- = AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
+ ur_arg_refs[a] = AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
}
ur_prev_end = end_off;
}
@@ -3107,21 +3143,18 @@ static AirInstRef zirCall(
}
// Resolve signedness from enum_literal in arg 0.
{
- uint32_t a0_end
- = sema->code.extra[arg_data_start + 0];
+ uint32_t a0_end = sema->code.extra[arg_data_start + 0];
uint32_t a0_start = arg_data_start + args_len;
uint32_t a0_body_end = arg_data_start + a0_end;
- for (uint32_t ai = a0_start; ai < a0_body_end;
- ai++) {
+ for (uint32_t ai = a0_start; ai < a0_body_end; ai++) {
uint32_t zi = sema->code.extra[ai];
if (zi < sema->code.inst_len
&& sema->code.inst_tags[zi]
== ZIR_INST_ENUM_LITERAL) {
- uint32_t si = sema->code.inst_datas[zi]
- .str_tok.start;
- const char* lit
- = (const char*)&sema->code
- .string_bytes[si];
+ uint32_t si
+ = sema->code.inst_datas[zi].str_tok.start;
+ const char* lit = (const char*)&sema->code
+ .string_bytes[si];
if (strcmp(lit, "signed") == 0)
signedness = 1;
break;
@@ -3175,9 +3208,7 @@ static AirInstRef zirCall(
if (type_fn_name
&& (strcmp(type_fn_name, "Int") == 0
|| strcmp(type_fn_name, "Log2Int") == 0
- || strcmp(type_fn_name,
- "PowerOfTwoSignificandZ")
- == 0
+ || strcmp(type_fn_name, "PowerOfTwoSignificandZ") == 0
|| strcmp(type_fn_name, "F16T") == 0)) {
returns_type = true;
} else {
@@ -3268,8 +3299,8 @@ static AirInstRef zirCall(
// Ported from Sema.zig:7394-7399: emit dummy alloc for
// non-comptime runtime params of generic functions,
// interleaved with arg evaluation (not batched after).
- if (is_generic && !is_ct_param[a]
- && !func_info.is_inline && !block->is_comptime) {
+ if (is_generic && !is_ct_param[a] && !func_info.is_inline
+ && !block->is_comptime) {
TypeIndex arg_ty = semaTypeOf(sema, arg_refs[a]);
AirInstData dummy;
memset(&dummy, 0, sizeof(dummy));
@@ -3282,6 +3313,19 @@ static AirInstRef zirCall(
sema->code = arg_code;
}
+ // Ported from src/Sema.zig line 7480:
+ // if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);
+ // call_dbg_node is the ZIR instruction preceding the call (inst - 1).
+ // Must use the caller's ZIR for cross-module calls.
+ if (inst > 0 && !block->is_comptime) {
+ Zir dbg_code = sema->code;
+ if (is_cross_module)
+ sema->code = saved_code;
+ zirDbgStmt(sema, block, inst - 1);
+ if (is_cross_module)
+ sema->code = dbg_code;
+ }
+
// Handle type-returning functions whose result can be computed from
// the comptime arguments without inlining.
// Upstream always reserves a dead BLOCK before inlining; we match
@@ -3290,9 +3334,11 @@ static AirInstRef zirCall(
// 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));
- (void)semaAddInstAsIndex(sema, AIR_INST_BLOCK, rt_dead);
+ {
+ AirInstData rt_dead;
+ memset(&rt_dead, 0, sizeof(rt_dead));
+ (void)semaAddInstAsIndex(sema, AIR_INST_BLOCK, rt_dead);
+ }
InternPoolIndex result_type = IP_INDEX_NONE;
if (type_fn_name && strcmp(type_fn_name, "Int") == 0) {
@@ -3306,22 +3352,18 @@ static AirInstRef zirCall(
bits_val = (uint16_t)k.data.int_val.value_lo;
}
if (args_len >= 1) {
- Zir caller_zir
- = is_cross_module ? saved_code : sema->code;
+ 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) {
+ && 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];
+ = (const char*)&caller_zir.string_bytes[str_idx];
if (strcmp(lit, "signed") == 0)
signedness = 1;
break;
@@ -3336,8 +3378,7 @@ static AirInstRef zirCall(
int_key.data.int_type.signedness = signedness;
result_type = ipIntern(sema->ip, int_key);
}
- } else if (type_fn_name
- && strcmp(type_fn_name, "Log2Int") == 0) {
+ } else if (type_fn_name && strcmp(type_fn_name, "Log2Int") == 0) {
// std.math.Log2Int(T): Int(.unsigned, log2_int_ceil(bits))
// where bits = @typeInfo(T).int.bits.
if (args_len >= 1 && AIR_REF_IS_IP(arg_refs[0])) {
@@ -3440,14 +3481,12 @@ static AirInstRef zirCall(
default:
break;
}
- uint32_t type_width
- = frac_bits + exp_bits + 1;
+ uint32_t type_width = frac_bits + exp_bits + 1;
int num_dead = (n == type_width) ? 7 : 8;
AirInstData extra_dead;
memset(&extra_dead, 0, sizeof(extra_dead));
for (int i = 0; i < num_dead; i++)
- semaAddInstAsIndex(
- sema, AIR_INST_BLOCK, extra_dead);
+ semaAddInstAsIndex(sema, AIR_INST_BLOCK, extra_dead);
// Upstream also memoizes floatFractionalBits(T)
// during this inline call, so later calls (from nan
// expansion) are memo hits. Pre-seed the memo to
@@ -3457,18 +3496,15 @@ static AirInstRef zirCall(
InternPoolKey frac_key;
memset(&frac_key, 0, sizeof(frac_key));
frac_key.tag = IP_KEY_INT;
- frac_key.data.int_val.ty
- = IP_INDEX_COMPTIME_INT_TYPE;
+ frac_key.data.int_val.ty = IP_INDEX_COMPTIME_INT_TYPE;
frac_key.data.int_val.value_lo = frac_bits;
- InternPoolIndex frac_ip
- = ipIntern(sema->ip, frac_key);
+ InternPoolIndex frac_ip = ipIntern(sema->ip, frac_key);
if (sema->num_memo < 32) {
uint32_t mi = sema->num_memo++;
sema->memo_func_inst[mi] = 755;
sema->memo_args_len[mi] = 1;
sema->memo_args[mi][0] = arg_refs[0];
- sema->memo_result[mi]
- = AIR_REF_FROM_IP(frac_ip);
+ sema->memo_result[mi] = AIR_REF_FROM_IP(frac_ip);
}
}
}
@@ -3547,12 +3583,12 @@ static AirInstRef zirCall(
// (e.g. comptime_int, type), the block is set to comptime, making
// is_inline_call = true. Upstream (Sema.zig:7482):
// is_inline_call = block.isComptime() or inline_requested;
- bool is_comptime_only_ret = (ret_ty == IP_INDEX_TYPE_TYPE
- || ret_ty == IP_INDEX_COMPTIME_INT_TYPE
- || ret_ty == IP_INDEX_COMPTIME_FLOAT_TYPE
- || ret_ty == IP_INDEX_ENUM_LITERAL_TYPE);
- bool is_inline_call = func_info.is_inline || block->is_comptime
- || is_comptime_only_ret;
+ bool is_comptime_only_ret
+ = (ret_ty == IP_INDEX_TYPE_TYPE || ret_ty == IP_INDEX_COMPTIME_INT_TYPE
+ || ret_ty == IP_INDEX_COMPTIME_FLOAT_TYPE
+ || ret_ty == IP_INDEX_ENUM_LITERAL_TYPE);
+ bool is_inline_call
+ = func_info.is_inline || block->is_comptime || is_comptime_only_ret;
if (!is_inline_call) {
// Dummy allocs for generic runtime params are now emitted
// interleaved in the arg evaluation loop above (Fix A).
@@ -3572,11 +3608,10 @@ static AirInstRef zirCall(
// Param extra: {name(u32), type(u32={body_len:31,
// is_generic:1}), body_inst...}
if (ptag == ZIR_INST_PARAM) {
- uint32_t param_pl = sema->code.inst_datas[
- param_body[p]]
- .pl_tok.payload_index;
- uint32_t type_raw
- = sema->code.extra[param_pl + 1];
+ uint32_t param_pl
+ = sema->code.inst_datas[param_body[p]]
+ .pl_tok.payload_index;
+ uint32_t type_raw = sema->code.extra[param_pl + 1];
uint32_t type_body_len = type_raw & 0x7FFFFFFF;
if (type_body_len >= 1) {
// The type body contains ZIR instruction
@@ -3584,15 +3619,13 @@ static AirInstRef zirCall(
// break_inline whose operand is the type ref.
uint32_t last_type_inst
= sema->code
- .extra[param_pl + 2
- + type_body_len - 1];
+ .extra[param_pl + 2 + type_body_len - 1];
if (last_type_inst < sema->code.inst_len
&& sema->code.inst_tags[last_type_inst]
== ZIR_INST_BREAK_INLINE) {
ZirInstRef type_ref
- = sema->code.inst_datas
- [last_type_inst]
- .break_data.operand;
+ = sema->code.inst_datas[last_type_inst]
+ .break_data.operand;
if (type_ref < ZIR_REF_START_INDEX) {
TypeIndex param_ty = type_ref;
arg = semaCoerce(
@@ -4143,9 +4176,8 @@ static void zirFunc(Sema* sema, SemaBlock* block, uint32_t inst) {
if (ret_ty_body_len > 2) {
const uint32_t* ret_ty_body = &sema->code.extra[ret_ty_ref_pos];
(void)analyzeBodyInner(sema, block, ret_ty_body, ret_ty_body_len);
- ZirInstRef operand
- = sema->code.inst_datas[sema->comptime_break_inst]
- .break_data.operand;
+ ZirInstRef operand = sema->code.inst_datas[sema->comptime_break_inst]
+ .break_data.operand;
AirInstRef ret_air = resolveInst(sema, operand);
pre_resolved_ret_ty = AIR_REF_TO_IP(ret_air);
}
@@ -4687,20 +4719,16 @@ static AirInstRef semaResolveSwitchComptime(
// the parent block.
uint32_t copy_len = child_block.instructions_len;
if (copy_len > 0) {
- uint32_t last = child_block.instructions
- [copy_len - 1];
+ uint32_t last = child_block.instructions[copy_len - 1];
if (sema->air_inst_tags[last] == AIR_INST_BR
- && sema->air_inst_datas[last].br.block_inst
- == block_inst)
+ && sema->air_inst_datas[last].br.block_inst == block_inst)
copy_len--;
}
for (uint32_t ci = 0; ci < copy_len; ci++) {
- if (block->instructions_len
- >= block->instructions_cap) {
+ 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));
+ block->instructions, new_cap * sizeof(uint32_t));
if (!block->instructions)
exit(1);
block->instructions_cap = new_cap;
@@ -4761,19 +4789,16 @@ static AirInstRef semaResolveSwitchComptime(
// case (line 6016-6024): elide trailing BR.
uint32_t copy_len = child_block.instructions_len;
if (copy_len > 0) {
- uint32_t last = child_block.instructions
- [copy_len - 1];
+ uint32_t last = child_block.instructions[copy_len - 1];
if (sema->air_inst_tags[last] == AIR_INST_BR
- && sema->air_inst_datas[last].br.block_inst
- == block_inst)
+ && sema->air_inst_datas[last].br.block_inst == block_inst)
copy_len--;
}
for (uint32_t ci = 0; ci < copy_len; ci++) {
if (block->instructions_len >= block->instructions_cap) {
uint32_t new_cap = block->instructions_cap * 2;
- block->instructions = realloc(
- block->instructions,
- new_cap * sizeof(uint32_t));
+ block->instructions
+ = realloc(block->instructions, new_cap * sizeof(uint32_t));
if (!block->instructions)
exit(1);
block->instructions_cap = new_cap;
@@ -4877,9 +4902,9 @@ static AirInstRef zirBitSizeOf(Sema* sema, uint32_t inst) {
// lookupStructField: find a field by name in the registered struct info.
// Returns the StructFieldInfo pointer and sets *field_index, or returns NULL.
-static const StructFieldInfo* lookupStructField(
- const Sema* sema, InternPoolIndex struct_type,
- const char* field_name, uint32_t* field_index) {
+static const StructFieldInfo* lookupStructField(const Sema* sema,
+ InternPoolIndex struct_type, const char* field_name,
+ uint32_t* field_index) {
for (uint32_t i = 0; i < sema->num_struct_info; i++) {
if (sema->struct_info[i].struct_type != struct_type)
continue;
@@ -4893,6 +4918,47 @@ static const StructFieldInfo* lookupStructField(
return NULL;
}
+// ensureF80StructRegistered: ensure the std.math.F80 struct type is
+// registered in the sema. Returns the F80 struct IP index.
+// The struct has two fields: fraction (u64, index 0) and exp (u16, index 1).
+// Ported from lib/std/math.zig F80 definition.
+static InternPoolIndex ensureF80StructRegistered(Sema* sema) {
+ // Check if already registered.
+ for (uint32_t i = 0; i < sema->num_struct_info; i++) {
+ if (sema->struct_info[i].num_fields == 2
+ && strcmp(sema->struct_info[i].fields[0].name, "fraction") == 0
+ && strcmp(sema->struct_info[i].fields[1].name, "exp") == 0) {
+ return sema->struct_info[i].struct_type;
+ }
+ }
+ // Register new F80 struct.
+ // Use a unique struct ID (0xF80F80) to distinguish from ZIR-based IDs.
+ InternPoolKey skey;
+ memset(&skey, 0, sizeof(skey));
+ skey.tag = IP_KEY_STRUCT_TYPE;
+ skey.data.struct_type = 0xF80F80;
+ InternPoolIndex struct_ip = ipIntern(sema->ip, skey);
+
+ InternPoolKey pkey;
+ memset(&pkey, 0, sizeof(pkey));
+ pkey.tag = IP_KEY_PTR_TYPE;
+ pkey.data.ptr_type.child = struct_ip;
+ pkey.data.ptr_type.flags = 0;
+ InternPoolIndex ptr_ip = ipIntern(sema->ip, pkey);
+
+ if (sema->num_struct_info >= 8)
+ return IP_INDEX_VOID_TYPE;
+ StructFieldInfo* info = &sema->struct_info[sema->num_struct_info++];
+ info->struct_type = struct_ip;
+ info->ptr_type = ptr_ip;
+ info->num_fields = 2;
+ info->fields[0].name = "fraction";
+ info->fields[0].type = IP_INDEX_U64_TYPE;
+ info->fields[1].name = "exp";
+ info->fields[1].type = IP_INDEX_U16_TYPE;
+ return struct_ip;
+}
+
// zirFieldValComptime: handle field_val on comptime and runtime struct values.
// For comptime: resolves .float on type_info results and .bits on float_info.
// For runtime structs: emits AIR_INST_STRUCT_FIELD_VAL.
@@ -4984,19 +5050,24 @@ static AirInstRef zirFieldValComptime(
InternPoolKey key;
memset(&key, 0, sizeof(key));
key.tag = IP_KEY_ENUM_LITERAL;
- key.data.enum_literal
- = simpleStringHash(s ? "signed" : "unsigned");
+ key.data.enum_literal = simpleStringHash(s ? "signed" : "unsigned");
return AIR_REF_FROM_IP(ipIntern(sema->ip, key));
}
+ // Handle cross-module struct type resolution:
+ // std.math.F80 → register the F80 struct (fraction: u64, exp: u16).
+ // Ported from lib/std/math.zig F80 definition.
+ if (strcmp(field_name, "F80") == 0 && obj_ip == IP_INDEX_VOID_VALUE) {
+ return AIR_REF_FROM_IP(ensureF80StructRegistered(sema));
+ }
+
return AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
}
// zirFieldPtr: handle field_ptr on runtime struct pointers.
// Emits AIR_INST_STRUCT_FIELD_PTR_INDEX_N for field index 0..3.
// Ported from src/Sema.zig fieldPtr / addStructFieldPtr.
-static AirInstRef zirFieldPtr(
- Sema* sema, SemaBlock* block, uint32_t inst) {
+static AirInstRef zirFieldPtr(Sema* sema, SemaBlock* block, uint32_t inst) {
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];
@@ -5330,15 +5401,50 @@ static bool analyzeBodyInner(
// ret_implicit: implicit return at end of function/block.
// Ported from src/Sema.zig zirRetImplicit / analyzeRet.
- case ZIR_INST_RET_IMPLICIT:
+ case ZIR_INST_RET_IMPLICIT: {
+ // Ported from src/Sema.zig zirRetImplicit → analyzeRet.
+ // When inlining, rewrite ret as br to inline block.
+ AirInstRef operand = AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
+ if (block->inlining) {
+ SemaBlockInlining* inl = block->inlining;
+ if (block->is_comptime) {
+ inl->comptime_result = operand;
+ inl->comptime_returned = true;
+ return false;
+ }
+ // Runtime inlining: rewrite ret as br.
+ 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 = semaAddInst(block, AIR_INST_BR, br_data);
+ if (inl->merges.results_len >= inl->merges.results_cap) {
+ 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.br_list = realloc(
+ 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;
+ inl->merges.br_list_cap = new_cap;
+ }
+ inl->merges.results[inl->merges.results_len++] = operand;
+ inl->merges.br_list[inl->merges.br_list_len++]
+ = AIR_REF_TO_INST(br_ref);
+ return false;
+ }
if (sema->fn_ret_ty != TYPE_NONE && !block->is_comptime) {
// Inside a function body: emit ret instruction.
AirInstData ret_data;
memset(&ret_data, 0, sizeof(ret_data));
- ret_data.un_op.operand = AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
+ ret_data.un_op.operand = operand;
(void)semaAddInst(block, AIR_INST_RET, ret_data);
}
return false;
+ }
// ret_node: explicit `return <expr>;`.
// Ported from src/Sema.zig zirRetNode / analyzeRet.
@@ -5490,16 +5596,14 @@ static bool analyzeBodyInner(
} else if (opcode == ZIR_EXT_ALLOC) {
// Ported from src/Sema.zig zirAllocExtended.
// Extended alloc with optional type and alignment.
- uint16_t small
- = sema->code.inst_datas[inst].extended.small;
+ uint16_t small = sema->code.inst_datas[inst].extended.small;
uint32_t payload_index
= sema->code.inst_datas[inst].extended.operand;
uint32_t ei = payload_index + 1; // skip src_node
if (small & 0x1) { // has_type
ZirInstRef type_ref = sema->code.extra[ei];
ei++;
- AirInstRef resolved
- = resolveInst(sema, type_ref);
+ AirInstRef resolved = resolveInst(sema, type_ref);
TypeIndex elem_ty = IP_INDEX_VOID_TYPE;
if (AIR_REF_IS_IP(resolved))
elem_ty = AIR_REF_TO_IP(resolved);
@@ -5511,22 +5615,19 @@ static bool analyzeBodyInner(
AirInstData adata;
memset(&adata, 0, sizeof(adata));
adata.ty.ty_ref = AIR_REF_FROM_IP(ptr_ty);
- air_ref = semaAddInst(
- block, AIR_INST_ALLOC, adata);
+ air_ref = semaAddInst(block, AIR_INST_ALLOC, adata);
} else {
// No type: inferred alloc with alignment.
// Same as alloc_inferred but from extended.
AirInstData adata;
memset(&adata, 0, sizeof(adata));
- air_ref = semaAddInst(
- block, AIR_INST_INFERRED_ALLOC, adata);
+ air_ref
+ = semaAddInst(block, AIR_INST_INFERRED_ALLOC, adata);
assert(sema->num_ia < 16);
uint32_t ia_idx = sema->num_ia++;
- sema->ia_air[ia_idx]
- = AIR_REF_TO_INST(air_ref);
+ sema->ia_air[ia_idx] = AIR_REF_TO_INST(air_ref);
sema->ia_store[ia_idx] = UINT32_MAX;
- sema->ia_is_const[ia_idx]
- = (small & 0x4) != 0;
+ sema->ia_is_const[ia_idx] = (small & 0x4) != 0;
}
} else if (opcode == ZIR_EXT_INPLACE_ARITH_RESULT_TY) {
// Ported from src/Sema.zig zirInplaceArithResultTy.
@@ -5570,8 +5671,7 @@ static bool analyzeBodyInner(
uint32_t saved_cbi = sema->comptime_break_inst;
sema->comptime_break_inst = UINT32_MAX;
- bool completed
- = analyzeBodyInner(sema, block, inner_body, inner_body_len);
+ analyzeBodyInner(sema, block, inner_body, inner_body_len);
bool hit_comptime_break
= (sema->comptime_break_inst != UINT32_MAX);
@@ -5579,8 +5679,6 @@ static bool analyzeBodyInner(
block->need_debug_scope = saved_need_debug_scope;
if (readBool(&need_debug_scope)) {
-
-
if (!hit_comptime_break) {
// Body completed normally or hit terminal instruction
// with 0 merges. Propagate need_debug_scope to parent.
@@ -5597,22 +5695,19 @@ static bool analyzeBodyInner(
uint32_t new_insts_count
= block->instructions_len - block_index;
- uint32_t blk_inst = semaAddInstAsIndex(sema,
- AIR_INST_BLOCK,
- (AirInstData) {
- .ty_pl = { .ty_ref = 0, .payload = 0 }
- });
+ uint32_t blk_inst
+ = semaAddInstAsIndex(sema, AIR_INST_BLOCK,
+ (AirInstData) {
+ .ty_pl = { .ty_ref = 0, .payload = 0 } });
AirInstData br_data;
memset(&br_data, 0, sizeof(br_data));
br_data.br.block_inst = blk_inst;
- br_data.br.operand
- = AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
- uint32_t br_inst = semaAddInstAsIndex(sema,
- AIR_INST_BR, br_data);
+ br_data.br.operand = AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
+ uint32_t br_inst
+ = semaAddInstAsIndex(sema, AIR_INST_BR, br_data);
uint32_t body_len2 = new_insts_count + 1;
- uint32_t extra_start
- = semaAddExtra(sema, body_len2);
+ uint32_t extra_start = semaAddExtra(sema, body_len2);
for (uint32_t ci = block_index;
ci < block->instructions_len; ci++) {
semaAddExtra(sema, block->instructions[ci]);
@@ -5621,23 +5716,18 @@ static bool analyzeBodyInner(
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;
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));
+ 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;
}
}
@@ -5650,8 +5740,7 @@ static bool analyzeBodyInner(
= sema->code.inst_datas[break_inst_zir];
uint32_t break_payload
= break_data_zir.break_data.payload_index;
- uint32_t break_block_inst
- = sema->code.extra[break_payload];
+ uint32_t break_block_inst = sema->code.extra[break_payload];
ZirInstRef operand = break_data_zir.break_data.operand;
if (break_block_inst == inst) {
@@ -5816,8 +5905,7 @@ static bool analyzeBodyInner(
case ZIR_INST_MIN:
case ZIR_INST_MAX: {
bool is_max = (sema->code.inst_tags[inst] == ZIR_INST_MAX);
- uint32_t pl
- = sema->code.inst_datas[inst].pl_node.payload_index;
+ uint32_t pl = sema->code.inst_datas[inst].pl_node.payload_index;
ZirInstRef zir_lhs = sema->code.extra[pl];
ZirInstRef zir_rhs = sema->code.extra[pl + 1];
AirInstRef min_lhs = resolveInst(sema, zir_lhs);
@@ -5825,8 +5913,8 @@ static bool analyzeBodyInner(
int64_t lv, rv;
if (isComptimeInt(sema, min_lhs, &lv)
&& isComptimeInt(sema, min_rhs, &rv)) {
- int64_t result_val = is_max ? (lv > rv ? lv : rv)
- : (lv < rv ? lv : rv);
+ int64_t result_val
+ = is_max ? (lv > rv ? lv : rv) : (lv < rv ? lv : rv);
InternPoolKey key;
memset(&key, 0, sizeof(key));
key.tag = IP_KEY_INT;
@@ -6163,8 +6251,7 @@ static bool analyzeBodyInner(
// field_ptr: runtime struct field pointer access.
case ZIR_INST_FIELD_PTR:
- instMapPut(
- &sema->inst_map, inst, zirFieldPtr(sema, block, inst));
+ instMapPut(&sema->inst_map, inst, zirFieldPtr(sema, block, inst));
i++;
continue;
@@ -6246,8 +6333,7 @@ static bool analyzeBodyInner(
uint32_t ia_idx = sema->num_ia++;
sema->ia_air[ia_idx] = AIR_REF_TO_INST(air_ref);
sema->ia_store[ia_idx] = UINT32_MAX;
- sema->ia_is_const[ia_idx]
- = (inst_tag == ZIR_INST_ALLOC_INFERRED);
+ sema->ia_is_const[ia_idx] = (inst_tag == ZIR_INST_ALLOC_INFERRED);
i++;
continue;
}
@@ -6355,21 +6441,43 @@ static bool analyzeBodyInner(
ckey.tag = IP_KEY_PTR_TYPE;
ckey.data.ptr_type.child = elem_ty;
ckey.data.ptr_type.flags = 1; // const
- TypeIndex const_ptr_ty
- = ipIntern(sema->ip, ckey);
+ TypeIndex const_ptr_ty = ipIntern(sema->ip, ckey);
AirInstData bc_data;
memset(&bc_data, 0, sizeof(bc_data));
- bc_data.ty_op.ty_ref
- = AIR_REF_FROM_IP(const_ptr_ty);
+ bc_data.ty_op.ty_ref = AIR_REF_FROM_IP(const_ptr_ty);
bc_data.ty_op.operand = ptr;
- ptr = semaAddInst(
- block, AIR_INST_BITCAST, bc_data);
+ ptr = semaAddInst(block, AIR_INST_BITCAST, bc_data);
}
instMapPut(&sema->inst_map, inst, ptr);
i++;
continue;
}
+ // make_ptr_const: convert mutable alloc pointer to const.
+ // Ported from src/Sema.zig zirMakePtrConst / makePtrConst.
+ // Emits AIR bitcast from *T to *const T.
+ case ZIR_INST_MAKE_PTR_CONST: {
+ ZirInstRef alloc_ref = sema->code.inst_datas[inst].un_node.operand;
+ AirInstRef alloc_ptr = resolveInst(sema, alloc_ref);
+ TypeIndex ptr_ty = semaTypeOf(sema, alloc_ptr);
+ TypeIndex child = ptrChildType(sema->ip, ptr_ty);
+ // Create *const T pointer type.
+ InternPoolKey ckey;
+ memset(&ckey, 0, sizeof(ckey));
+ ckey.tag = IP_KEY_PTR_TYPE;
+ ckey.data.ptr_type.child = child;
+ ckey.data.ptr_type.flags = PTR_FLAGS_IS_CONST;
+ TypeIndex const_ptr_ty = ipIntern(sema->ip, ckey);
+ AirInstData bc_data;
+ memset(&bc_data, 0, sizeof(bc_data));
+ bc_data.ty_op.ty_ref = AIR_REF_FROM_IP(const_ptr_ty);
+ bc_data.ty_op.operand = alloc_ptr;
+ AirInstRef result = semaAddInst(block, AIR_INST_BITCAST, bc_data);
+ instMapPut(&sema->inst_map, inst, result);
+ i++;
+ continue;
+ }
+
// block: runtime block.
// Ported from src/Sema.zig zirBlock / resolveAnalyzedBlock.
// In Zig, comptime .block redirects to .block_inline (no AIR
@@ -6516,43 +6624,36 @@ static bool analyzeBodyInner(
sema->comptime_break_inst = saved_comptime_break;
// Resolve the block: write extra data and patch type.
- // Ported from src/Sema.zig resolveBlockBody / resolveAnalyzedBlock.
+ // Ported from src/Sema.zig resolveBlockBody /
+ // resolveAnalyzedBlock.
// Handle ComptimeBreak: a break_inline was encountered in
// the body. Ported from Sema.zig resolveBlockBody line 5915.
if (is_comptime_break && label.merges.results_len == 0) {
// Copy child instructions to parent block.
- if (need_debug_scope
- && child_block.instructions_len > 0) {
+ if (need_debug_scope && child_block.instructions_len > 0) {
// Wrap in BLOCK for scoping.
AirInstData br_data;
memset(&br_data, 0, sizeof(br_data));
br_data.br.block_inst = block_inst_idx;
- br_data.br.operand
- = AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
- uint32_t br_inst = semaAddInstAsIndex(
- sema, AIR_INST_BR, br_data);
- uint32_t body_len2
- = child_block.instructions_len + 1;
- uint32_t extra_start
- = semaAddExtra(sema, body_len2);
- for (uint32_t ci = 0;
- ci < child_block.instructions_len; ci++) {
- semaAddExtra(
- sema, child_block.instructions[ci]);
+ br_data.br.operand = AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
+ uint32_t br_inst
+ = semaAddInstAsIndex(sema, AIR_INST_BR, br_data);
+ uint32_t body_len2 = child_block.instructions_len + 1;
+ uint32_t extra_start = semaAddExtra(sema, body_len2);
+ for (uint32_t ci = 0; ci < child_block.instructions_len;
+ ci++) {
+ semaAddExtra(sema, child_block.instructions[ci]);
}
semaAddExtra(sema, br_inst);
sema->air_inst_datas[block_inst_idx].ty_pl.ty_ref
= AIR_REF_FROM_IP(IP_INDEX_VOID_TYPE);
sema->air_inst_datas[block_inst_idx].ty_pl.payload
= extra_start;
- if (block->instructions_len
- >= block->instructions_cap) {
- uint32_t new_cap
- = block->instructions_cap * 2;
+ 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));
+ block->instructions, new_cap * sizeof(uint32_t));
if (!block->instructions)
exit(1);
block->instructions_cap = new_cap;
@@ -6561,14 +6662,12 @@ static bool analyzeBodyInner(
= block_inst_idx;
} else {
// Copy instructions directly to parent.
- for (uint32_t ci = 0;
- ci < child_block.instructions_len; ci++) {
+ 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,
+ uint32_t new_cap = block->instructions_cap * 2;
+ block->instructions = realloc(block->instructions,
new_cap * sizeof(uint32_t));
if (!block->instructions)
exit(1);
@@ -6587,8 +6686,8 @@ static bool analyzeBodyInner(
if (break_block_inst == inst) {
// Break targets this block: resolve operand.
- AirInstRef ct_result = resolveInst(
- sema, bdata2.break_data.operand);
+ AirInstRef ct_result
+ = resolveInst(sema, bdata2.break_data.operand);
sema->comptime_break_inst = saved_comptime_break;
free(label.merges.results);
free(label.merges.br_list);
@@ -6779,8 +6878,8 @@ static bool analyzeBodyInner(
// void-typed blocks return void_value, rewriting
// all br operands to void_value.
if (resolved_ty == IP_INDEX_VOID_TYPE) {
- for (uint32_t mi = 0;
- mi < label.merges.results_len; mi++) {
+ for (uint32_t mi = 0; mi < label.merges.results_len;
+ mi++) {
sema->air_inst_datas[label.merges.br_list[mi]]
.br.operand
= AIR_REF_FROM_IP(IP_INDEX_VOID_VALUE);
@@ -7184,8 +7283,10 @@ static bool analyzeBodyInner(
// int_type: create an integer type from signedness and bit count.
// Ported from src/Sema.zig zirIntType.
case ZIR_INST_INT_TYPE: {
- uint8_t signedness = sema->code.inst_datas[inst].int_type.signedness;
- uint16_t bit_count = sema->code.inst_datas[inst].int_type.bit_count;
+ uint8_t signedness
+ = sema->code.inst_datas[inst].int_type.signedness;
+ uint16_t bit_count
+ = sema->code.inst_datas[inst].int_type.bit_count;
InternPoolKey key;
memset(&key, 0, sizeof(key));
key.tag = IP_KEY_INT_TYPE;
diff --git a/stage0/sema_test.zig b/stage0/sema_test.zig
@@ -1226,3 +1226,117 @@ test "sema air: if-else block result" {
\\}
);
}
+
+test "sema air: call inside runtime conditional" {
+ try semaAirRawCheck(
+ \\fn bar(p: *u32) void {
+ \\ p.* += 1;
+ \\}
+ \\export fn f(a: u32) u32 {
+ \\ var x: u32 = a;
+ \\ if (a < 10) bar(&x);
+ \\ return x;
+ \\}
+ );
+}
+
+test "sema air: inline fn with call inside conditional" {
+ try semaAirRawCheck(
+ \\fn bar(p: *u32) void {
+ \\ p.* += 1;
+ \\}
+ \\inline fn baz(a: u32, x: *u32) void {
+ \\ if (a < 10) bar(x);
+ \\}
+ \\export fn f(a: u32) u32 {
+ \\ var x: u32 = a;
+ \\ baz(a, &x);
+ \\ return x;
+ \\}
+ );
+}
+
+test "sema air: += with call inside conditional" {
+ try semaAirRawCheck(
+ \\fn bar(p: *u32) u32 {
+ \\ return p.* + 1;
+ \\}
+ \\export fn f(a: u32) u32 {
+ \\ var x: u32 = a;
+ \\ if (a < 10) x += bar(&x);
+ \\ return x;
+ \\}
+ );
+}
+
+test "sema air: inline fn with += call inside conditional" {
+ try semaAirRawCheck(
+ \\fn bar(p: *u32) u32 {
+ \\ return p.* + 1;
+ \\}
+ \\inline fn baz(a: u32, x: *u32) void {
+ \\ if (a < 10) x.* += bar(x);
+ \\}
+ \\export fn f(a: u32) u32 {
+ \\ var x: u32 = a;
+ \\ baz(a, &x);
+ \\ return x;
+ \\}
+ );
+}
+
+test "sema air: inline fn with generic call inside conditional" {
+ try semaAirRawCheck(
+ \\fn normalize(comptime T: type, p: *T) i32 {
+ \\ p.* +%= 1;
+ \\ return 1;
+ \\}
+ \\inline fn mulf(comptime T: type, a: T) T {
+ \\ var x: T = a;
+ \\ var scale: i32 = 0;
+ \\ if (x < 10) scale += normalize(T, &x);
+ \\ return x +% @as(T, @intCast(@as(u32, @bitCast(scale))));
+ \\}
+ \\export fn f(a: u32) u32 {
+ \\ return mulf(u32, a);
+ \\}
+ );
+}
+
+test "sema air: inline fn with two generic calls in conditionals" {
+ try semaAirRawCheck(
+ \\fn normalize(comptime T: type, p: *T) i32 {
+ \\ p.* +%= 1;
+ \\ return 1;
+ \\}
+ \\inline fn mulf(comptime T: type, a: T, b: T) T {
+ \\ var x: T = a;
+ \\ var y: T = b;
+ \\ var scale: i32 = 0;
+ \\ if (x < 10) scale += normalize(T, &x);
+ \\ if (y < 10) scale += normalize(T, &y);
+ \\ return x +% y +% @as(T, @intCast(@as(u32, @bitCast(scale))));
+ \\}
+ \\export fn f(a: u32, b: u32) u32 {
+ \\ return mulf(u32, a, b);
+ \\}
+ );
+}
+
+test "sema air: inline fn with += call inside two conditionals" {
+ try semaAirRawCheck(
+ \\fn bar(p: *u32) u32 {
+ \\ return p.* + 1;
+ \\}
+ \\inline fn baz(a: u32, x: *u32, y: *u32) void {
+ \\ if (a < 10) x.* += bar(x);
+ \\ if (a < 20) y.* += bar(y);
+ \\}
+ \\export fn f(a: u32) u32 {
+ \\ var x: u32 = a;
+ \\ var y: u32 = a;
+ \\ baz(a, &x, &y);
+ \\ return x +% y;
+ \\}
+ );
+}
diff --git a/stage0/stages_test.zig b/stage0/stages_test.zig
@@ -146,8 +146,8 @@ const corpus_files = .{
"../lib/compiler_rt/floatunsixf.zig", // 353
"../lib/compiler_rt/truncxfhf2.zig", // 356
"../lib/compiler_rt/floatunsihf.zig", // 357
- //"../lib/compiler_rt/trunctfhf2.zig", // 359
- //"../lib/compiler_rt/extendsfxf2.zig", // 360
+ "../lib/compiler_rt/trunctfhf2.zig", // 359
+ "../lib/compiler_rt/extendsfxf2.zig", // 360
//"../lib/compiler/aro/backend.zig", // 362
//"../lib/compiler_rt/extenddfxf2.zig", // 364
//"../lib/std/compress.zig", // 372