diff --git a/stage0/sema.c b/stage0/sema.c index f8ac607bd8..8fb4b4a0a8 100644 --- 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 ;`. // 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 index f752527860..1dbeef0245 100644 --- 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 index fe608e7e29..1dbf97f024 100644 --- 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