sema: port compareIntsOnlyPossibleResult, fix int coercion dedup, bump 75→80
Port compareIntsOnlyPossibleResult from upstream Sema.zig (line 32511): when a comparison has one comptime operand, intern the other type's min/max bounds as side effects. This matches the Zig compiler's IP entry sequence for comparison operations. Fix semaCoerceIntRef: switch from ipForceIntern to ipIntern for integer type coercion. The cross-shard dedup issue is now handled by the skip_dedup mechanism, so ipForceIntern is no longer needed. Using ipIntern allows proper deduplication of identical coerced values (e.g., two comparisons with `> 0` share the same int_u32(0)). Tests 75-79 now pass (var_bitcast_and_if, shr_exact, nested_if, conditional_bitwise_and, conditional_sub). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user