Repository navigation
codegen: P3 B3, delete the INT32 Number consumers - #14395
Merged
Merged
Conversation
added 5 commits
November 10, 2026 01:03
Since P3 B4a nothing can produce an INT32-tagged Number, so a Number has one encoding for every operand, proven or not. Compiled code no longer tests for the 0x7FFE word or decodes it: - compare: the both-INT32 arm of the === prefix, normalize_int32_immediate, the compact arm of strict equality against a Number, the INT32 arm of the relational against a Number - compare_chain: the per-local decode of a comparison graph - index_key: the boxed arm of perry_array_index_normalize_i32 - typed_abi / typed_entry: emit_int32_box_test, emit_int32_bits_test, the tier-2 convert block, emit_typed_f64_to_raw_guarded, emit_typed_i32_guard_and_raw, emit_typed_arg_to_raw_after_entry_tier - the direct typed closure call's tier 2 (early_branches) - switch: emit_canonical_numeric_view and NumericView - parameter entry: emit_entry_number, the closure region conversion - the Number receiver kind guard, the const-length witness decode - PERRY_WP_REP_P3 (facts_rep::canonical_numbers): it restored a tag test that no longer exists
|
Caution Review failedThe pull request is closed.
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
P3 "canonical Numbers", DESIGN-p3 rev 3.1 §3 B3 (REVIEW-p3 R3, S3). After B1 (#14354), B2 (#14358) and B4a (#14372) nothing can produce an INT32-tagged Number, so a Number has one encoding, the plain double, for every operand: proven, unproven or ⊤. This PR deletes every test and decode of that encoding from generated code, and the helpers that emitted them.
Why it is sound to delete
Checked on main before deleting each consumer:
eb9ec0de82) is in main:v8_serde.rs read_doubleand the bun:ffiT_F64/T_F32returns (float_value) no longer pass a payload through.JSValue::int32is gone (B4a).INT32_TAG |,0x7FFE_0000_0000_0000 |in perry-runtime, perry-stdlib, perry-ffi, the ext crates and perry-abi) is one of DESIGN-p3 §1.2's internal words: overflow routes, the bound inline-args marker, the class id capture and evaluation state, the constructor identity word, the class key bits and method home word, key_attrs. The one exception is the build-timecanonnumsabotage inmath.rs. None is a JS value.i32load), the class first-evaluation state (read by the runtime) and the realm atom. None of them flows into a deleted consumer.Deleted
===/!==prefix, two unproven operandsexpr/compare.rs lower_strict_eq_inline_any===/!==against a Numberexpr/compare.rs lower_strict_eq_against_numbernormalize_int32_immediate(the function), the compact arm (saturating convert, round trip, payload compare)expr/compare.rs lower_relational_against_numberproven_exprparameterexpr/compare_chain.rs(:149 on the design's main)expr/index_key.rs(:117-123)boxedarm ofperry_array_index_normalize_i32codegen/typed_entry.rsemit_int32_box_test,emit_int32_bits_test, theint32_convertblock and its phi. Tier 2 admits NaN Numbers and branches to the one fast blockcodegen/typed_abi.rsemit_typed_f64_guard;emit_typed_f64_to_raw_guarded;emit_typed_i32_guard_and_raw(callers use the plain-double predicate); the tag select inemit_typed_i32_raw_assuming_guarded(onefptosi);emit_typed_arg_to_raw_after_entry_tier(now equal toemit_typed_arg_to_raw)lower_call/early_branches.rslower_call/scalar_method.rsstmt/switch_stmt.rsemit_canonical_numeric_viewandNumericView. A numericswitchcompares the discriminant's own bits: every non-Number is a NaN pattern and fails each orderedfcmpcodegen/facts_number_locals.rs emit_entry_number,function.rs,method.rs,signature_entry.rs,closure.rslower_call/property_get/builtin_kind_guard.rsfacts_const_length.rs,facts_int32_locals.rs,lower_call/index_split.rsPERRY_WP_REP_P3codegen/facts_rep.rs canonical_numbersnumber_callstays underPERRY_WP_REP_P2nanbox.rsINT32_MASK,INT32_TAG_TOP16_I64Guarded arithmetic: main has no inline INT32 arm to delete.
emit_js_value_is_numberalready rejects the whole tag band and the dynamic arm is a runtime call. Only its comment changed.Left, with the reason
js_typed_f64_arg_guard/js_typed_f64_arg_to_raw(the Map/Set number-key paths inmath_simple.rs,bigint_set.rs,logical_collections.rs,method_override.rs) andjs_typed_i32_arg_guard/_to_raw(scalar_method.rs). Their INT32 arm is inside the runtime functions, which is B4b. Once B4b lands, theto_rawcall is an identity and goes with it.INT32_TAG/INT32_TAG_I64: kept for the internal words. The rename is B4b.index.rs,index_set_*,member_update.rs, …): the tests are band tests, not tests of the tag.No switch
A pure deletion has nothing to switch. Every comparison below is the branch against the main build at the merge base.
Controls
tests/parity/language/number/test_p3_b3_top_operands.tsdrives each deleted path with unproven operands (values fromJSON.parseand a mixed array: 0, ±1, 7, 2.5, int32 min and max, 2^32, 1e300, -0, NaN, ±Infinity, numeric and non-numeric strings, null, undefined, booleans, a BigInt, an object withvalueOf, an array, a Symbol):===/!==against int literals, a fraction and a Number local, both orders; relationals against a Number; every kind against every kind for===and<;switchand a mixed-literal tower;any;The negative controls are the non-Numbers:
"7" === 7is false,switch ("7")takes the string case,null >= 0is true,undefined < 1false, a BigInt and a Symbol take their own arms. Output equals node in normal mode, check mode, with moving-GC loop polls, withPERRY_FACTS_CANONICAL_NUMBERS=0, and on main.Results (qb9 x86-64,
instructions:u; brancha0923eb11cvs main5de5bb7544, its merge base)Two runs per arm, identical to 0.1 M; checksums equal. Chess IR: 125 INT32 identity tests on main, 0 on the branch; 707 fewer IR lines (
and−146,icmp−131,select−101,sitofp−88,or−58)..text1238 and 5 907 390; callgrind startup Ir 127 145 and 623 941, the same in all 3 runs of both armsPERRY_FACTS_CANONICAL_NUMBERS=0, main)PERRY_VERIFY_FACTS=1test_gap_s8b_computed_fields,test_gap_10554_fn_identity_own_module)-D warningsscripts/check_file_size.shcodegen/mod.rs3588 → 3586,tests/native_proof_regressions.rs15680 → 15678)The 10 output diffs: 5 programs fail to compile in both arms (crc 1/1:
test_gap_s8b_computed_fields,test_gap_10554_fn_identity_own_module,test_gap_cjs_factory_slot,test_gap_11275_reexport_value_kinds,test_issue_5431_dollar_named_export_call), so there is no output to compare. 4 print time or random values (test_issue63_arr,test_date,test_math,test_issue58_object_string).test_gap_this_param_receiver_routesdiffers only in the PID of a deprecation warning line.Size (every executable section; branch vs main)
All four shrink. In skin,
.textgrows by 11 456 B whileperry_js_textshrinks by 80 704 B; the per-symbol cause of the.textpart was not investigated.The canonnum sabotage
scripts/p3-canonnum-runtime.shbuilt the runtime whosejs_math_roundreturns an INT32 word (archive mtime check passed). The S0 false armcanonical-number-negativereports a false proof on the branch, and the clean arm passes. But the S0 script's assertion fails (rc 1) on both the branch and main5de5bb7544: the miss is now reported first by the array-representation witness (predicate "array rep", from #14390), where the script expects "canonical number". The forged word is caught; the script's expectation is stale on main and is not changed here.Tests changed
expr/compare_chain_tests.rs,compare_tests.rs,hit_path_tests.rs,codegen/typed_abi/tests.rs,facts_number_locals_tests.rs,stmt/byte_result_tests.rs: they asserted the INT32 test or decode; they now assert its absence (and the one plain-number classification where there is one).tests/native_proof_regressions.rs:unboxes_number_arg(INT32 test plussitofp) is replaced bytests_int32_tag, asserted absent. This file has 23 failing tests on main on macOS; the same 23 fail on the branch.Not re-measured
The final head also merges main
8e1c285569(PR-C2 and three wpfacts commits; a clean merge,cargo check -p perry-codegen --all-targetsclean on macOS). The gates above ran ona0923eb11c, before that merge.