diff --git a/stage0/corpus.zig b/stage0/corpus.zig index 43f76d18ab..9082af643a 100644 --- a/stage0/corpus.zig +++ b/stage0/corpus.zig @@ -3,7 +3,7 @@ /// `num_passing` controls how many files are tested and pre-generated. /// Both build.zig and stages_test.zig import this file. /// To enable more tests: just increment `num_passing`. -pub const num_passing: usize = 75; +pub const num_passing: usize = 80; pub const files = [_][]const u8{ "stage0/sema_tests/empty.zig", diff --git a/stage0/sema.c b/stage0/sema.c index e393616de6..6ead655c2e 100644 --- a/stage0/sema.c +++ b/stage0/sema.c @@ -532,12 +532,10 @@ static AirInstRef semaCoerceIntRef( return air_ref; // already the right type // Create a new IP entry with the target type but same value. - // Use ipForceIntern to skip deduplication: the Zig compiler's - // sharded IP creates separate entries in different shards (e.g. - // CallingConvention enum values in the memoized shard vs function - // body values in the function shard). The C sema's single IP - // would incorrectly deduplicate, returning an index from the - // memoized state instead of creating a new function-local entry. + // Use ipIntern for deduplication: entries with the same type and + // value are shared. Cross-shard separation is handled by the + // skip_dedup mechanism (preamble entries are skipped, main analysis + // entries dedup normally). InternPoolKey new_key; memset(&new_key, 0, sizeof(new_key)); new_key.tag = IP_KEY_INT; @@ -545,7 +543,7 @@ static AirInstRef semaCoerceIntRef( new_key.data.int_val.value_lo = key.data.int_val.value_lo; new_key.data.int_val.value_hi = key.data.int_val.value_hi; new_key.data.int_val.is_negative = key.data.int_val.is_negative; - uint32_t new_ip_idx = ipForceIntern(sema->ip, new_key); + uint32_t new_ip_idx = ipIntern(sema->ip, new_key); return AIR_REF_FROM_IP(new_ip_idx); } @@ -1324,6 +1322,66 @@ static AirInstRef zirArithmetic( } emit_runtime:; + // Ported from Sema.zig cmpNumeric → compareIntsOnlyPossibleResult + // (line 32299-32325): when one operand is comptime-known and the + // other is a runtime integer, intern the type's min/max bounds. + // These entries are side effects of the bounds check; even if the + // comparison can't be folded, the boundary values must be interned + // to match the Zig compiler's IP entry sequence. + if (air_tag >= AIR_INST_CMP_LT && air_tag <= AIR_INST_CMP_GT) { + TypeIndex lhs_ty = semaTypeOf(sema, lhs); + TypeIndex rhs_ty = semaTypeOf(sema, rhs); + bool lhs_is_ct = (lhs_ty == IP_INDEX_COMPTIME_INT_TYPE); + bool rhs_is_ct = (rhs_ty == IP_INDEX_COMPTIME_INT_TYPE); + if ((lhs_is_ct != rhs_is_ct) && !lhs_is_ct + && sema->ip->items[lhs_ty].tag == IP_KEY_INT_TYPE) { + // RHS is comptime, LHS is runtime int → intern LHS + // type bounds. + uint16_t bits = sema->ip->items[lhs_ty].data.int_type.bits; + bool is_signed = sema->ip->items[lhs_ty].data.int_type.signedness; + uint64_t min_val = 0; + uint64_t max_val + = (bits >= 64) ? UINT64_MAX : ((1ULL << bits) - 1); + if (is_signed) { + min_val = (bits >= 64) ? (uint64_t)INT64_MIN + : ~((1ULL << (bits - 1)) - 1); + max_val = (bits >= 64) ? (uint64_t)INT64_MAX + : ((1ULL << (bits - 1)) - 1); + } + InternPoolKey mk; + memset(&mk, 0, sizeof(mk)); + mk.tag = IP_KEY_INT; + mk.data.int_val.ty = lhs_ty; + mk.data.int_val.value_lo = min_val; + (void)ipIntern(sema->ip, mk); + mk.data.int_val.value_lo = max_val; + (void)ipIntern(sema->ip, mk); + } else if ((lhs_is_ct != rhs_is_ct) && !rhs_is_ct + && sema->ip->items[rhs_ty].tag == IP_KEY_INT_TYPE) { + // LHS is comptime, RHS is runtime int → intern RHS + // type bounds. + uint16_t bits = sema->ip->items[rhs_ty].data.int_type.bits; + bool is_signed = sema->ip->items[rhs_ty].data.int_type.signedness; + uint64_t min_val = 0; + uint64_t max_val + = (bits >= 64) ? UINT64_MAX : ((1ULL << bits) - 1); + if (is_signed) { + min_val = (bits >= 64) ? (uint64_t)INT64_MIN + : ~((1ULL << (bits - 1)) - 1); + max_val = (bits >= 64) ? (uint64_t)INT64_MAX + : ((1ULL << (bits - 1)) - 1); + } + InternPoolKey mk; + memset(&mk, 0, sizeof(mk)); + mk.tag = IP_KEY_INT; + mk.data.int_val.ty = rhs_ty; + mk.data.int_val.value_lo = min_val; + (void)ipIntern(sema->ip, mk); + mk.data.int_val.value_lo = max_val; + (void)ipIntern(sema->ip, mk); + } + } + TypeIndex peer_ty = semaResolvePeerTypes(sema, lhs, rhs); lhs = semaCoerce(sema, block, peer_ty, lhs); rhs = semaCoerce(sema, block, peer_ty, rhs);